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 +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/lib/plc/browser.rb +3 -0
- data/lib/plc/memory_word.rb +30 -0
- data/lib/plc/plc.rb +44 -0
- data/lib/plc/server_authentication.rb +47 -0
- data/lib/plc/server_variable_page.html +541 -0
- data/lib/plc/version.rb +3 -0
- data/plc.gemspec +24 -0
- data/readme.md +46 -0
- data/spec/browser_spec.rb +17 -0
- data/spec/factories.rb +9 -0
- data/spec/memory_word_spec.rb +44 -0
- data/spec/parser_spec.rb +18 -0
- data/spec/plc_spec.rb +80 -0
- data/spec/spec_helper.rb +33 -0
- metadata +69 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/plc/browser.rb
ADDED
|
@@ -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 1200 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, "'");
|
|
16
|
+
phrase_off = phrase_off.replace(/'/g, "'");
|
|
17
|
+
var update_phrase_on = "<img title='Automatic refresh enabled' border='0' src='../Images/update_active.gif'> <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'> <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 1200 station_1/PLC_1" >SIMATIC 1200 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"> </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 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&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"> <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>
|
|
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"> 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"> 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"> 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"> </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"> </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%"> </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
|
+
|
data/lib/plc/version.rb
ADDED
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,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
|
data/spec/parser_spec.rb
ADDED
|
@@ -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
|
+
|
data/spec/spec_helper.rb
ADDED
|
@@ -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
|