plc 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in plc.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ class Browser < Watir::Browser
2
+
3
+ end
@@ -0,0 +1,30 @@
1
+ class MemoryWord
2
+ attr_reader :name
3
+
4
+ def initialize(name)
5
+ name ? (@name = "MW0") : (raise "Name required to initialize MemoryWord")
6
+ @plc = Plc.instance
7
+ end
8
+
9
+ class << self
10
+ def row_names
11
+ Plc.instance.variable_page.css(".varstate_address_field_valid").collect {|f| f.attributes["name"].value }
12
+ end
13
+ end
14
+
15
+ def row_name
16
+ row = @plc.variable_page.search(".varstate_address_field_valid").select { |a| a.attributes["value"].value == self.name }.first
17
+ row.attributes["name"].value
18
+ end
19
+
20
+ def value
21
+ td = "dynamic_contentt#{self.row_name[1..-1]}"
22
+ @plc.variable_page.search('.updatable').select { |div| div.attributes["id"].value == td }.first.text[1..-1]
23
+ end
24
+
25
+ def value=(num)
26
+ @plc.set_word_value(self, num)
27
+ end
28
+
29
+
30
+ end
data/lib/plc/plc.rb ADDED
@@ -0,0 +1,44 @@
1
+ class Plc
2
+ include ServerAuthentication
3
+ include Parser
4
+ include Singleton
5
+
6
+ INPUT_MODES = { 10 => "auto",
7
+ 20 => "generator",
8
+ 30 => "solar",
9
+ 40 => "wind" }
10
+
11
+ VARIABLE_PAGE_URL = "http://192.168.0.1/Portal/Portal.mwsl?PriNav=Varstate&v1=QB0&t1=BIN&v2=IW0&t2=BIN&v3=MW0&t3=DEC_UNSIGNED&v4=New%20variable&t4=BIN"
12
+
13
+ def browser
14
+ @browser ||= Browser.new
15
+ end
16
+
17
+ def input_mode
18
+ value = MemoryWord.new("MW0").value
19
+ INPUT_MODES[value] ? INPUT_MODES[value] : "Inconclusive"
20
+ end
21
+
22
+ def reset_browser
23
+ @browser.try(:close)
24
+ @browser = Browser.new
25
+ end
26
+
27
+ def set_word_value(word, value)
28
+ reset_session
29
+ tr = "t#{word.row_name[1..-1]}"
30
+ browser.inputs(name: "modifyvalue_#{tr}").first.to_subtype.set "#{value}"
31
+ browser.inputs(name: "gobutton_#{tr}").first.click
32
+
33
+ MemoryWord.new(word).value
34
+ end
35
+
36
+ def variable_page
37
+ parse Plc::VARIABLE_PAGE_URL
38
+ end
39
+
40
+ def reset_session
41
+ reset_browser && login unless logged_in?
42
+ end
43
+
44
+ end
@@ -0,0 +1,47 @@
1
+ module ServerAuthentication
2
+
3
+ def get_variable_page
4
+ browser.goto Plc::VARIABLE_PAGE_URL
5
+ end
6
+
7
+ def login
8
+ unless logged_in?
9
+ get_variable_page unless @browser.url == Plc::VARIABLE_PAGE_URL
10
+ fill_in_login_field
11
+ submit_login_form
12
+
13
+ logged_in? ? "logged in as admin" : LoginError
14
+ else
15
+ "already logged in"
16
+ end
17
+ end
18
+
19
+ def fill_in_login_field
20
+ login_field.set "admin"
21
+ end
22
+
23
+ def submit_login_form
24
+ login_button.click
25
+ end
26
+
27
+ def login_form
28
+ browser.forms.select {|form| form.name == "LoginForm" }.first
29
+ end
30
+
31
+ def login_field
32
+ browser.text_fields.select {|input| input.name == "Login" }.first
33
+ end
34
+
35
+ def login_button
36
+ browser.buttons.select {|button | button.text == "Log in"}.first
37
+ end
38
+
39
+ def logged_in?
40
+ browser.buttons.select {|button| button.text == "Log out"}.count > 0
41
+ end
42
+
43
+ def logout
44
+ browser.buttons.select {|button| button.text == "Log out"}.first.click if logged_in?
45
+ "logged out of admin"
46
+ end
47
+ end
@@ -0,0 +1,541 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
+ <html>
3
+ <head>
4
+ <title>SIMATIC&nbsp;1200&nbsp;station_1</title>
5
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!-- ISO-8859-1 oder UTF-8 -->
6
+ <meta http-equiv="expires" content="0">
7
+ <link rel="stylesheet" type="text/css" href="../CSS/S7Web.css">
8
+ <SCRIPT src="../Scripts/update.js" type="text/javascript"></SCRIPT>
9
+
10
+ <script type="text/javascript">
11
+ <!--
12
+ // Replace, because of the apostrophe in the french language
13
+ var phrase_on = "Disable automatic refresh";
14
+ var phrase_off = "Enable automatic refresh";
15
+ phrase_on = phrase_on.replace(/'/g, "&apos;");
16
+ phrase_off = phrase_off.replace(/'/g, "&apos;");
17
+ var update_phrase_on = "<img title='Automatic refresh enabled' border='0' src='../Images/update_active.gif'>&nbsp;<span title='" + phrase_on + "' class='Text_ReloadIcon'>Off</span>";
18
+ var update_phrase_off= "<img title='Automatic refresh disabled' border='0' src='../Images/update_inactive.gif'>&nbsp;<span title='" + phrase_off + "' class='Text_ReloadIcon'>On</span>";
19
+ var update_interval = '0';
20
+ var url_to_update = '0';
21
+ var lang_str_details = 'Details'; // f�r BGZ - selectRowDetails() in sortfiltertableml.js: String "Details" sprachersetzen
22
+ -->
23
+ </script>
24
+ <script type="text/javascript">url_to_update = window.location.href;update_interval='10000';</script>
25
+
26
+ </head>
27
+ <body>
28
+ <table class="main_table" cellspacing="0" cellpadding="0">
29
+ <!-- Header Line -->
30
+ <tr class="Header_Area">
31
+ <!-- Siemens Logo -->
32
+ <td><img src="../Images/Siemens_Firmenmarke_Header.gif" alt="Siemens" border="0"></td>
33
+ <!-- Object description (Headline) -->
34
+ <td valign="top" >
35
+ <table cellspacing ="0" cellpadding="0" border="0">
36
+ <tr>
37
+ <td height="39"></td><!-- 45px -6px (font-frame) -->
38
+ </tr>
39
+ <tr>
40
+ <td valign="top" class="Header_Title_Description" title="SIMATIC&nbsp;1200&nbsp;station_1/PLC_1" >SIMATIC&nbsp;1200&nbsp;station_1/PLC_1</td>
41
+
42
+ </tr>
43
+ </table>
44
+ </td>
45
+ <!-- Object description (Headline) End -->
46
+ <!-- Language Selection -->
47
+ <td align="right" valign="top" >
48
+ <table>
49
+ <tr>
50
+ <td class="Header_Language_Time_Date">
51
+ <table cellspacing="0" cellpadding="0">
52
+ <tr>
53
+ <td height ="12">&nbsp;</td>
54
+ </tr>
55
+ <tr>
56
+ <td align="right" valign="top">
57
+
58
+ </td>
59
+
60
+ </tr>
61
+ <tr>
62
+ <td height="10"></td>
63
+ </tr>
64
+ <tr>
65
+ <td class="Header_Date_Time"><div id="dynamic_date" class="updatable">02:00:54 am&nbsp;&nbsp;&nbsp;20.03.1970</div></td>
66
+ </tr>
67
+ </table>
68
+ </td>
69
+ </tr>
70
+ </table>
71
+ </td>
72
+ <!-- Language Selection End-->
73
+ <!-- Header Line End-->
74
+ <!-- Generated Line (MainNavigation(includes Login) and ClientArea(includes Title Area) -->
75
+
76
+ <tr>
77
+ <!-- Main Menu -->
78
+ <td>
79
+ <!-- Menu Generation -->
80
+
81
+ <table class="MainMenu_Area" cellspacing="0" cellpadding="0">
82
+ <tr>
83
+ <!-- Login Area -->
84
+ <!--<td class="Login_Area" colspan="2"><img src="/Images/SIMATIC_CONTROLLER.png" alt="Simatic Controller"></td>-->
85
+ <td class="Login_Area" colspan="2">
86
+
87
+ <script LANGUAGE="JScript" TYPE="text/javascript">
88
+ <!--
89
+ function logout()
90
+ {
91
+ window.top.document.cookie = "siemens_ad_session=;expires=Fri, 31 Dec 1999 23:59:59 GMT;";
92
+ }
93
+ -->
94
+ </script>
95
+ <form id="logout_form" action="/FormLogin?LOGOUT" method="post" enctype="application/x-www-form-urlencoded">
96
+ <table id="logout_table">
97
+ <tr id="logout_tr_name">
98
+ <td id="logout_td_name">admin</td>
99
+
100
+ </tr>
101
+ <tr id="logout_tr_empty"><td></td></tr>
102
+ <tr id="logout_tr_logout">
103
+ <td id="logout_td_logout">
104
+ <INPUT type='hidden' name='Redirection' value='.'>
105
+ <INPUT type='hidden' name='Cookie' value='BDGyjKWjzGDwCvmhhNLA5tN/ocMAAQABAALacsCoAAsAAAAAAAAAANpyQH8='>
106
+
107
+ <input id="logout_form_button" type="submit" onClick="logout()" value="Log out">
108
+ </td>
109
+ </tr>
110
+ </table>
111
+ </form>
112
+
113
+
114
+ </td>
115
+ <!--Login Area End -->
116
+ </tr>
117
+
118
+ <tr>
119
+ <td height="20px">
120
+ </td>
121
+ </tr>
122
+ <tr class="MainMenu_Navigation_Level1">
123
+ <td class="MainMenu_Navigation_arrow_Level1">
124
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
125
+ </td>
126
+ <td class="MainMenu_Navigation_Level1">
127
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Portal.mwsl?PriNav=Start'>Start Page</a>
128
+ </td>
129
+ </tr>
130
+
131
+ <tr>
132
+ <td height="20px">
133
+
134
+ </td>
135
+ </tr>
136
+ <tr class="MainMenu_Navigation_Level1">
137
+ <td class="MainMenu_Navigation_arrow_Level1">
138
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
139
+ </td>
140
+ <td class="MainMenu_Navigation_Level1">
141
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Portal.mwsl?PriNav=Ident'>Identification</a>
142
+ </td>
143
+ </tr>
144
+
145
+ <tr>
146
+ <td height="20px">
147
+ </td>
148
+ </tr>
149
+ <tr class="MainMenu_Navigation_Level1">
150
+
151
+ <td class="MainMenu_Navigation_arrow_Level1">
152
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
153
+ </td>
154
+ <td class="MainMenu_Navigation_Level1">
155
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Portal.mwsl?PriNav=Diag'>Diagnostic Buffer</a>
156
+ </td>
157
+ </tr>
158
+
159
+ <tr>
160
+ <td height="20px">
161
+ </td>
162
+ </tr>
163
+ <tr class="MainMenu_Navigation_Level1">
164
+ <td class="MainMenu_Navigation_arrow_Level1">
165
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
166
+ </td>
167
+
168
+ <td class="MainMenu_Navigation_Level1">
169
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Portal.mwsl?PriNav=Bgz'>Module Information</a>
170
+ </td>
171
+ </tr>
172
+
173
+ <tr>
174
+ <td height="20px">
175
+ </td>
176
+ </tr>
177
+ <tr class="MainMenu_Navigation_Level1">
178
+ <td class="MainMenu_Navigation_arrow_Level1">
179
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
180
+ </td>
181
+ <td class="MainMenu_Navigation_Level1">
182
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Portal.mwsl?PriNav=Communication&amp;SecNav=CommunicationParam'>Communication</a>
183
+
184
+ </td>
185
+ </tr>
186
+
187
+ <tr>
188
+ <td height="20px">
189
+ </td>
190
+ </tr>
191
+ <tr class="MainMenu_Navigation_Level1">
192
+ <td class="MainMenu_Navigation_arrow_Level1">
193
+ <img src="/Images/NaviPfeilweiss.gif" alt="" border="0">
194
+ </td>
195
+ <td class="MainMenu_Navigation_Level1">
196
+ <a class="MainMenu_Navigation_Text_Level1_Selected" href='../Portal/Portal.mwsl?PriNav=Varstate'>Variable Status</a>
197
+ </td>
198
+ </tr>
199
+
200
+ <tr>
201
+ <td height="20px">
202
+ </td>
203
+ </tr>
204
+ <tr class="MainMenu_Navigation_Level1">
205
+ <td class="MainMenu_Navigation_arrow_Level1">
206
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
207
+ </td>
208
+ <td class="MainMenu_Navigation_Level1">
209
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Portal.mwsl?PriNav=DataLog'>Data Logs</a>
210
+ </td>
211
+ </tr>
212
+
213
+ <tr>
214
+ <td height="20px">
215
+ </td>
216
+
217
+ </tr>
218
+ <tr class="MainMenu_Navigation_Level1">
219
+ <td class="MainMenu_Navigation_arrow_Level1">
220
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
221
+ </td>
222
+ <td class="MainMenu_Navigation_Level1">
223
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Portal.mwsl?PriNav=Awp'>User Pages</a>
224
+ </td>
225
+ </tr>
226
+
227
+ <tr>
228
+ <td height="56px">
229
+ </td>
230
+ </tr>
231
+ <tr class="MainMenu_Navigation_Level1">
232
+ <td class="MainMenu_Navigation_arrow_Level1">
233
+
234
+ <img src="/Images/NaviPfeilblau.gif" alt="" border="0">
235
+ </td>
236
+ <td class="MainMenu_Navigation_Level1">
237
+ <a class="MainMenu_Navigation_Text_Level1" href='../Portal/Intro.mwsl'>Introduction</a>
238
+ </td>
239
+ </tr>
240
+
241
+ <!-- the following line is necessary for styling reasons -->
242
+ <tr>
243
+ <td height="100%">
244
+ </td>
245
+ </tr>
246
+ </table>
247
+
248
+ </td>
249
+ <!-- Client Area -->
250
+
251
+ <td class="Client_Area" colspan="2">
252
+
253
+ <SCRIPT LANGUAGE="javascript" type="text/javascript">
254
+ <!--
255
+ function processKey(e,buttonName)
256
+ {
257
+ if (null == e)
258
+ e = window.event ;
259
+ if (e.keyCode == 13) {
260
+ document.getElementById(buttonName).click();
261
+ return false;
262
+ }
263
+ }
264
+ function findNode(startingNode, tagName)
265
+ {
266
+ obj=startingNode;
267
+ var i=0;
268
+ while (obj && (!obj.tagName || (obj.tagName && obj.tagName!=tagName)))
269
+ {
270
+ obj=startingNode.childNodes[i];
271
+ i++;
272
+ }
273
+ if (obj && obj.tagName && obj.tagName==tagName)
274
+ {
275
+ return obj;
276
+ }
277
+ else if (startingNode.firstChild)
278
+ return findNode(startingNode.firstChild, tagName);
279
+ return 0;
280
+ }
281
+ function highlightEachCell(obj, color, inputcellColor, selectcellColor)
282
+ {
283
+ var i=0;
284
+ var tableCell=findNode(obj, "TD");
285
+ while (tableCell)
286
+ {
287
+ {
288
+ if (!tableCell.style)
289
+ {
290
+ tableCell.style={};
291
+ }
292
+ tableCell.style["backgroundColor"]=color;
293
+ tableCell.style.cursor='default';
294
+ i++;
295
+ }
296
+ {
297
+ var inputCell=findNode(tableCell, "INPUT");
298
+ if (inputCell)
299
+ {
300
+ if (inputCell.type.toUpperCase() =='TEXT')
301
+ {
302
+ if (!inputCell.style)
303
+ {
304
+ inputCell.style={};
305
+ }
306
+ inputCell.style["backgroundColor"]=inputcellColor;
307
+ inputCell.style.cursor='default';
308
+ }
309
+ }
310
+ else
311
+ {
312
+ inputCell=findNode(tableCell, "SELECT");
313
+ if (inputCell)
314
+ {
315
+ if (!inputCell.style)
316
+ {
317
+ inputCell.style={};
318
+ }
319
+ inputCell.style["backgroundColor"]=selectcellColor;
320
+ inputCell.style.cursor='default';
321
+ }
322
+ }
323
+ }
324
+ tableCell=tableCell.nextSibling;
325
+ }
326
+ }
327
+ var selectedObject = null;
328
+ var columnHighlighTed = false;
329
+ function highlightRow(obj){
330
+ var tr=obj;
331
+ while (tr.tagName.toUpperCase()!='TR'&&tr.parentNode){
332
+ tr=tr.parentNode;
333
+ }
334
+ if (!tr.col){
335
+ highlightEachCell(tr, '#C3CCED', '#C3CCED', '#C3CCED');
336
+ }
337
+ if (selectedObject == null)
338
+ {
339
+ highlightEachCell(tr, '#C3CCED', '#C3CCED', '#C3CCED');
340
+ selectedObject = tr;
341
+ }
342
+ else if (selectedObject == tr)
343
+ {
344
+ }
345
+ else {
346
+ if (selectedObject!= null)
347
+ {
348
+ highlightEachCell(selectedObject, '#F0F0F0', '#FFFFFF', '#E1E1E1');
349
+ }
350
+ highlightEachCell(tr, '#C3CCED', '#C3CCED', '#C3CCED');
351
+ selectedObject = tr;
352
+ }
353
+ }
354
+ -->
355
+ </SCRIPT>
356
+ <table cellpadding="0" cellspacing="0" width="100%" >
357
+ <tr>
358
+ <td valign="top">
359
+ <table class="Title_Area" cellpadding="0" cellspacing="0">
360
+ <tr>
361
+ <td class="Title_Area_Name" height="30px" title="Variable Status">Variable Status</td>
362
+ <td>
363
+ </td>
364
+ </tr>
365
+ <tr>
366
+ <td class="Title_Area_Selectbox" height="30px">
367
+ <SCRIPT LANGUAGE="javascript" type="text/javascript">
368
+ <!--
369
+ function DoSelection(oselection)
370
+ {
371
+ var url = document.location.href;
372
+ var value = oselection.value
373
+ var name = oselection.name
374
+ var searchname = name + "=";
375
+ var paramstartpos = url.indexOf(searchname);
376
+ if (paramstartpos == -1)
377
+ {
378
+ paramstartpos = url.length;
379
+ }
380
+ else
381
+ {
382
+ paramstartpos = paramstartpos-1;
383
+ }
384
+ var temp = url.substring(paramstartpos+1);
385
+ paramendpos = temp.indexOf("&");
386
+ newurl = url.substring(0,paramstartpos) + "&" + name + "=" + value;
387
+ if (paramendpos != -1 )
388
+ {
389
+ newurl= newurl+ temp.substring(paramendpos);
390
+ }
391
+ document.location.href=newurl;
392
+ }
393
+ /* Frey */
394
+ function SubmitForm()
395
+ {
396
+ document.DropDown.submit();
397
+ }
398
+ -->
399
+
400
+ </SCRIPT>
401
+
402
+ </td>
403
+ <td class="Title_Area_ReloadIcon">&nbsp;<span id="dynamic_link">
404
+ <a class="Link_ReloadIcon" href="../ReloadSite.mwsl">
405
+ <img title="Refresh" alt="Refresh" border="0" src="../Images/update_active.gif"></a></span></td>
406
+ <td class="Title_Area_PrinterIcon">
407
+ <a style='TEXT-DECORATION: none' href='../Portal/Print.mwsl?PriNav=Varstate&v1=QB0&t1=BIN&v2=IW0&t2=BIN&v3=MW0&t3=DEC_UNSIGNED&v4=New variable&t4=BIN' target=_blank>&nbsp;
408
+ <IMG title="Print" style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px; HEIGHT: 13px"
409
+ height=13 alt=Print src="../Images/Drucken.gif"
410
+ border=0>
411
+ </a>
412
+ </td>
413
+ </tr>
414
+ </table>
415
+ </td>
416
+ </tr>
417
+ <tr>
418
+ <td valign="top" width="100%" height="100%">
419
+
420
+ <table cellspacing="0" cellpadding="0" width="100%" >
421
+ <tr>
422
+ <td align="center" valign="top" height="100%" width="100%">
423
+ <FORM action="../VarStateRedirect.mwsl" style="margin: 1px;" name="DropDown" METHOD="GET" >
424
+ <INPUT type='hidden' name ='PriNav' value='Varstate'>
425
+ <table class="Vartable" cellpadding="0" cellspacing="0" id="varstate_table">
426
+ <tr>
427
+ <td class="vartable_description_line" colspan="7">Enter the address of a tag here which you want to monitor/modify
428
+ </td>
429
+ </tr>
430
+ <tr>
431
+ <td style="width:20%" class="vartable_header_field">Address</td>
432
+ <td style="width:12%" class="vartable_header_field">Display Format</td>
433
+ <td style="width:25%" class="vartable_header_field">Monitor Value</td>
434
+
435
+ <td style="width:13%" class="vartable_header_field">Modify Value</td><td style="width:5%" class="vartable_header_field">Modify</td>
436
+ </tr>
437
+ <NOSCRIPT>
438
+ <tr>
439
+ <input type="submit" style="visibility:hidden">
440
+ </tr>
441
+ </NOSCRIPT>
442
+
443
+ <tr id="tr1">
444
+ <td onClick="highlightRow(this);" class="vartable_static_field"><INPUT class="varstate_address_field_valid" TYPE="TEXT" name="v1" value="QB0" maxlength="50" onkeydown="return processKey(event,'DoVars')" ></td>
445
+ <td onClick="highlightRow(this);" class="vartable_static_field">
446
+ <SELECT name="t1" class="Variable_Type_Selection_Box" onchange="SubmitForm()">
447
+ <option value="BIN" selected>BIN</option><option value="DEC">DEC</option><option value="DEC_UNSIGNED">DEC_UNSIGNED</option><option value="HEX">HEX</option><option value="CHARACTER">CHARACTER</option>
448
+
449
+ </SELECT>
450
+ </td>
451
+ <td onClick="highlightRow(this);" class="vartable_static_field"><div id="dynamic_contentt1" class="updatable">&nbsp;2#0000_0000</div></td>
452
+ <td onClick="highlightRow(this);" class="vartable_static_field"><input type="text" size="30" name="modifyvalue_t1" onkeydown="return processKey(event,'gobutton_t1')" /></td>
453
+ <td class="vartable_static_field"><input type="submit" class="varstate_submit_field" value="Go" name="gobutton_t1" id="gobutton_t1"/></td>
454
+ </tr>
455
+
456
+ <tr id="tr2">
457
+ <td onClick="highlightRow(this);" class="vartable_static_field"><INPUT class="varstate_address_field_valid" TYPE="TEXT" name="v2" value="IW0" maxlength="50" onkeydown="return processKey(event,'DoVars')" ></td>
458
+ <td onClick="highlightRow(this);" class="vartable_static_field">
459
+ <SELECT name="t2" class="Variable_Type_Selection_Box" onchange="SubmitForm()">
460
+ <option value="BIN" selected>BIN</option><option value="DEC">DEC</option><option value="DEC_UNSIGNED">DEC_UNSIGNED</option><option value="HEX">HEX</option><option value="CHARACTER">CHARACTER</option><option value="DATE">DATE</option>
461
+
462
+ </SELECT>
463
+ </td>
464
+ <td onClick="highlightRow(this);" class="vartable_static_field"><div id="dynamic_contentt2" class="updatable">&nbsp;2#0000_0000_0000_0000</div></td>
465
+ <td onClick="highlightRow(this);" class="vartable_static_field"><input type="text" size="30" name="modifyvalue_t2" onkeydown="return processKey(event,'gobutton_t2')" /></td>
466
+ <td class="vartable_static_field"><input type="submit" class="varstate_submit_field" value="Go" name="gobutton_t2" id="gobutton_t2"/></td>
467
+ </tr>
468
+
469
+ <tr id="tr3">
470
+ <td onClick="highlightRow(this);" class="vartable_static_field"><INPUT class="varstate_address_field_valid" TYPE="TEXT" name="v3" value="MW0" maxlength="50" onkeydown="return processKey(event,'DoVars')" ></td>
471
+ <td onClick="highlightRow(this);" class="vartable_static_field">
472
+ <SELECT name="t3" class="Variable_Type_Selection_Box" onchange="SubmitForm()">
473
+ <option value="BIN">BIN</option><option value="DEC">DEC</option><option value="DEC_UNSIGNED" selected>DEC_UNSIGNED</option><option value="HEX">HEX</option><option value="CHARACTER">CHARACTER</option><option value="DATE">DATE</option>
474
+
475
+ </SELECT>
476
+ </td>
477
+ <td onClick="highlightRow(this);" class="vartable_static_field"><div id="dynamic_contentt3" class="updatable">&nbsp;40</div></td>
478
+ <td onClick="highlightRow(this);" class="vartable_static_field"><input type="text" size="30" name="modifyvalue_t3" onkeydown="return processKey(event,'gobutton_t3')" /></td>
479
+ <td class="vartable_static_field"><input type="submit" class="varstate_submit_field" value="Go" name="gobutton_t3" id="gobutton_t3"/></td>
480
+ </tr>
481
+
482
+ <tr id="tr4">
483
+ <td onClick="highlightRow(this);" class="vartable_static_field"><INPUT class="varstate_address_field_valid" TYPE="TEXT" name="v4" value="New variable" maxlength="50" onkeydown="return processKey(event,'DoVars')" ></td>
484
+ <td onClick="highlightRow(this);" class="vartable_static_field">
485
+ <SELECT name="t4" class="Variable_Type_Selection_Box" onchange="SubmitForm()">
486
+ <option value="BIN">BIN</option><option value="BOOL">BOOL</option><option value="DEC">DEC</option><option value="DEC_UNSIGNED">DEC_UNSIGNED</option><option value="HEX">HEX</option><option value="FLOATING_POINT">FLOATING_POINT</option><option value="CHARACTER">CHARACTER</option><option value="DATE">DATE</option><option value="TIME">TIME</option><option value="TIME_OF_DAY">TIME_OF_DAY</option>
487
+
488
+ </SELECT>
489
+ </td>
490
+ <td onClick="highlightRow(this);" class="vartable_static_field"><div id="dynamic_contentt4" class="updatable">&nbsp;</div></td>
491
+ <td class="vartable_static_field"></td>
492
+ <td class="vartable_static_field"></td>
493
+ </tr>
494
+
495
+ <tr>
496
+ <td colspan="5">&nbsp;</td>
497
+ </tr>
498
+ <tr>
499
+ <td colspan="5"><table width="100%">
500
+ <tr>
501
+ <td class="varstate_submit_gab"></td>
502
+ <td><INPUT class="varstate_submit_field" TYPE="submit" name="DoVars" id="DoVars" value="Monitor Value" >
503
+ </td>
504
+ <td><INPUT class="varstate_submit_field" TYPE="submit" name="ModifyAll" value="Modify All Values" style="float: right"></td><td class="varstate_submit_gab"></td>
505
+
506
+ </tr>
507
+ </table>
508
+ </td>
509
+ </tr>
510
+ <tr>
511
+ <td colspan="3" height="100%">&nbsp;</td>
512
+ </tr>
513
+ </table>
514
+ </Form>
515
+ </td>
516
+ </tr>
517
+ </table>
518
+ </td>
519
+ </tr>
520
+ </table>
521
+ <script language="javascript" type="text/javascript">
522
+ <!--
523
+ if (window != top.server_frame){
524
+ var i;
525
+ var t_rows = document.getElementById("varstate_table").rows;
526
+ var t_cols = t_rows[t_rows.length-4]; // --> Row "new variable"
527
+ var elem_new_var = t_cols.cells[0].getElementsByTagName("input");
528
+ elem_new_var[0].focus();
529
+ elem_new_var[0].select();
530
+ }
531
+ -->
532
+ </script>
533
+
534
+ </td>
535
+ <!-- Client Area End -->
536
+ </tr>
537
+ <!-- END Generated Line (MainNavigation(includes Login) and ClientArea(includes Title Area) -->
538
+ </table>
539
+ </body>
540
+ </html>
541
+
@@ -0,0 +1,3 @@
1
+ module Plc
2
+ VERSION = "0.0.1"
3
+ end
data/plc.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "plc/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "plc"
7
+ s.version = Plc::VERSION
8
+ s.authors = ["Steven Zeiler"]
9
+ s.email = ["zeiler.steven@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A library to interact with a Siemens S7-1200 Portable Logic Controller}
12
+ s.description = %q{It interacts with the PLC\'s built-in server to get, login, update the values of the various words in memory}
13
+
14
+ s.rubyforge_project = "plc"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+ end
data/readme.md ADDED
@@ -0,0 +1,46 @@
1
+ The Siemens SIMATEC S7-1200 Portable Login Controller controls hardware systems. It runs a web server that presents the administrator with a website for viewing and updating the data in the system's memory.
2
+
3
+ Here is provided a Ruby API for interacting with the data in the PLC. The library enables an author to create an application or user interface that controls the PLC's data over a network.
4
+
5
+ ## Setup
6
+
7
+ Admin access requires the application to use javascript, so it requires the `watir` gem.
8
+
9
+ gem 'watir-webdriver'
10
+
11
+ Logging in creates an instance of Watir::Browser that is used to login as 'admin'. Initializing `@plc.browser` opens a new firefox window.
12
+
13
+ @plc.browser
14
+ => #<Watir::Browser:0x..fb3b25e9b19004190 url="about:blank" title="">
15
+
16
+ ## Logging In
17
+ The PLC needs you to login as the "admin" user in order to add or update a word in its memory.
18
+
19
+ @plc.login
20
+ => "logged in as admin"
21
+
22
+ You should receive a message telling you that you are logged in. If you try to login again as the 'admin', you will be notified.
23
+
24
+ @plc.login
25
+ => "already logged in"
26
+
27
+ Unfortunately if the user agent logs in too many times the system times out and you are unable to login without restarting the PLC. In this case you will be returned a `ServerAuthentication::LoginError`
28
+
29
+ Once logged in, variable memory words can be [updated or added](https://github.com/stevenzeiler/plc/wiki/Updating-Variable-Words).
30
+
31
+ ## Updating a Variable
32
+
33
+ To update a word in the PLC's memory, call `update_word_value` with word's name and new value.
34
+
35
+ @plc = Plc.first
36
+ @plc.update_word_value("MW0", 40)
37
+
38
+ Our project calls `@plc.update_word_value("MW0", 40)` to tell the PLC to update the electricity input-type. `MW0` is the name of the memory word specifying the input-type, and `40` corresponds to solar panel input.
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
@@ -0,0 +1,17 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Browser do
4
+
5
+ describe "initializing the browser" do
6
+ before(:each) do
7
+ @browser = Browser.new
8
+ end
9
+
10
+ it "should be a Watir::Browser" do
11
+ @browser.should be_a Watir::Browser
12
+ end
13
+ end
14
+
15
+
16
+
17
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,9 @@
1
+ FactoryGirl.define do
2
+ factory :memory_word do
3
+ name "MW0"
4
+ end
5
+
6
+ factory :plc do
7
+ Plc.instance
8
+ end
9
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe MemoryWord do
4
+
5
+ it "initializes with a name" do
6
+ @word = MemoryWord.new("MW0")
7
+ @word.name.should == "MW0"
8
+ end
9
+
10
+ it "doesn't initialize without a name" do
11
+ lambda { MemoryWord.new }.should raise_error
12
+ end
13
+
14
+ context 'getting the mw0' do
15
+
16
+ before(:each) do
17
+ @word = MemoryWord.new("MW0")
18
+ end
19
+
20
+ it "#row_name" do
21
+ @word.row_name.should eq("v3")
22
+ end
23
+
24
+ it "self#row_names should return row names" do
25
+ ['v1', 'v2', 'v3', 'v4'].each do |name|
26
+ MemoryWord.row_names.include? name
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'setting the mw0' do
32
+ before(:each) do
33
+ @plc = Plc.instance
34
+ @plc.login
35
+ @word = MemoryWord.new("MW0")
36
+ end
37
+
38
+ it "#value= should set the new value" do
39
+ @word.value = 40
40
+ @word.value.should eq("40")
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parser do
4
+ describe "initializing the parser" do
5
+
6
+ before(:each) do
7
+ @plc = Plc.new
8
+ end
9
+
10
+ it "should be a module" do
11
+ Parser.should be_a Module
12
+ end
13
+
14
+ it "#parse(page) should make a Nokogiri::HTML object" do
15
+ @plc.parse(Plc::VARIABLE_PAGE_URL).class.should eq(Nokogiri::HTML::Document)
16
+ end
17
+ end
18
+ end
data/spec/plc_spec.rb ADDED
@@ -0,0 +1,80 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Plc do
4
+
5
+ context 'initializing plc' do
6
+
7
+ it "should have a Watir:Browser object" do
8
+ plc = Plc.instance
9
+ plc.browser.should be_a Watir::Browser
10
+ end
11
+
12
+ end
13
+
14
+ describe 'logging into plc server' do
15
+
16
+ before(:each) do
17
+ @plc ||= Plc.instance
18
+ end
19
+
20
+ after(:each) do
21
+ @plc.browser.close
22
+ end
23
+
24
+ it "should get a new watir browser object" do
25
+ @plc.browser.should be_a Watir::Browser
26
+ end
27
+
28
+ it "should get the variable status page" do
29
+ @plc.get_variable_page
30
+ @plc.browser.title.include? "SIMATIC"
31
+ end
32
+
33
+ it "the variable page should have a login form" do
34
+ @plc.get_variable_page
35
+ @plc.login_form.should be_a Watir::Form
36
+ end
37
+
38
+ it "should have a login field" do
39
+ @plc.get_variable_page
40
+ @plc.login_field.should be_a Watir::Input
41
+ end
42
+
43
+ it "should fill in the login field with 'admin'" do
44
+ @plc.logout
45
+ @plc.should_receive(:fill_in_login_field).and_return("admin")
46
+ @plc.login
47
+ end
48
+
49
+ describe "#login" do
50
+ before(:each) { @plc.login }
51
+
52
+ it "should be 'admin' after loggin in" do
53
+ @plc.logged_in?.should be_true
54
+ @plc.logout
55
+ end
56
+
57
+ it "gives a message if trying to log in while logged in" do
58
+ @plc.login.should == "already logged in"
59
+ @plc.logout
60
+ end
61
+
62
+ it "should logout from the server" do
63
+ @plc.logout
64
+ @plc.logged_in?.should be_false
65
+
66
+ @plc.logout
67
+ end
68
+ end
69
+
70
+
71
+ end
72
+
73
+ describe "#input_mode" do
74
+ it "should equal the correct value for MW0" do
75
+ pending "create method"
76
+ end
77
+ end
78
+
79
+ end
80
+
@@ -0,0 +1,33 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+ require File.expand_path("../../config/environment", __FILE__)
4
+ require 'rspec/rails'
5
+ require 'rspec/autorun'
6
+
7
+ # Requires supporting ruby files with custom matchers and macros, etc,
8
+ # in spec/support/ and its subdirectories.
9
+ Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
10
+
11
+ RSpec.configure do |config|
12
+ # == Mock Framework
13
+ #
14
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
15
+ #
16
+ # config.mock_with :mocha
17
+ # config.mock_with :flexmock
18
+ # config.mock_with :rr
19
+ config.mock_with :rspec
20
+
21
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
22
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
23
+
24
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
25
+ # examples within a transaction, remove the following line or assign false
26
+ # instead of true.
27
+ config.use_transactional_fixtures = true
28
+
29
+ # If true, the base class of anonymous controllers will be inferred
30
+ # automatically. This will be the default behavior in future versions of
31
+ # rspec-rails.
32
+ config.infer_base_class_for_anonymous_controllers = false
33
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: plc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Steven Zeiler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-05 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: It interacts with the PLC\'s built-in server to get, login, update the
15
+ values of the various words in memory
16
+ email:
17
+ - zeiler.steven@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - Rakefile
25
+ - lib/plc/browser.rb
26
+ - lib/plc/memory_word.rb
27
+ - lib/plc/plc.rb
28
+ - lib/plc/server_authentication.rb
29
+ - lib/plc/server_variable_page.html
30
+ - lib/plc/version.rb
31
+ - plc.gemspec
32
+ - readme.md
33
+ - spec/browser_spec.rb
34
+ - spec/factories.rb
35
+ - spec/memory_word_spec.rb
36
+ - spec/parser_spec.rb
37
+ - spec/plc_spec.rb
38
+ - spec/spec_helper.rb
39
+ homepage: ''
40
+ licenses: []
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project: plc
59
+ rubygems_version: 1.8.6
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: A library to interact with a Siemens S7-1200 Portable Logic Controller
63
+ test_files:
64
+ - spec/browser_spec.rb
65
+ - spec/factories.rb
66
+ - spec/memory_word_spec.rb
67
+ - spec/parser_spec.rb
68
+ - spec/plc_spec.rb
69
+ - spec/spec_helper.rb