... | ... |
@@ -373,7 +373,7 @@ void listenForEthernetClients() |
373 | 373 |
sBuffer[i] = 0; |
374 | 374 |
} |
375 | 375 |
// request for JSON string response |
376 |
- if(strcmp(sBuffer, "GET /jsdata ") == 0) { |
|
376 |
+ if(strcmp(sBuffer, "GET /rdata ") == 0) { |
|
377 | 377 |
iMode = 1; |
378 | 378 |
} |
379 | 379 |
// request for standard HTML document |
... | ... |
@@ -388,20 +388,19 @@ void listenForEthernetClients() |
388 | 388 |
client.println(F("HTTP/1.1 200 OK\n" \ |
389 | 389 |
"Content-Type: text/html\n" \ |
390 | 390 |
"Connnection: close\n" \ |
391 |
- // "Refresh: 10\n" \ |
|
392 | 391 |
"\n" \ |
393 | 392 |
)); |
394 | 393 |
|
395 | 394 |
switch (iMode) { |
396 | 395 |
case 0: |
397 | 396 |
// Respond to an invalid URL received from the client |
398 |
- client.print(F("<!DOCTYPE HTML>\n" \ |
|
399 |
- "<HTML><HEAD><TITLE>Radmon</TITLE></HEAD>" \ |
|
400 |
- "<BODY><H2>Invalid URL</H2>" \ |
|
401 |
- "<P> You have reached a server at an unknown " \ |
|
402 |
- "URL. If you think you made this request in error " \ |
|
403 |
- "please disconnect and try your request again.</P>" \ |
|
404 |
- "</BODY></HTML>")); |
|
397 |
+ client.print(F("<!DOCTYPE html>\n" \ |
|
398 |
+ "<html><head><title>DIY Radmon</title></head>" \ |
|
399 |
+ "<body><h2>Invalid URL</h2>" \ |
|
400 |
+ "<p>You have reached a server at an unknown URL.</p>" \ |
|
401 |
+ "<p>If you think you made this call in error,<br>" \ |
|
402 |
+ "please hangup and try your call again.</p>" \ |
|
403 |
+ "</body></html>")); |
|
405 | 404 |
break; |
406 | 405 |
case 1: |
407 | 406 |
transmitJson(client); |
... | ... |
@@ -434,33 +433,33 @@ void transmitWebPage(EthernetClient client) |
434 | 433 |
* Send the actual HTML page the user will see in their web |
435 | 434 |
* browser. |
436 | 435 |
*/ |
437 |
- client.print(F("<!DOCTYPE HTML>\n" \ |
|
438 |
- "<HTML><HEAD><TITLE>Radmon</TITLE>" \ |
|
439 |
- "</HEAD><BODY><H2>Radiation Monitor</H2>" \ |
|
440 |
- "<P><A HREF=\"http://intravisions.com/radmon/\">" \ |
|
441 |
- "<I>IntraVisions.com/radmon</I></A></P>" \ |
|
442 |
- "<HR><FONT SIZE=\"+1\">")); |
|
443 |
- /* Data Items */ |
|
444 |
- client.print(F("<PRE>UTC	")); |
|
436 |
+ client.print(F("<!DOCTYPE html>\n" \ |
|
437 |
+ "<html><head><title>DIY Radmon</title>" \ |
|
438 |
+ "<style>pre{font-size:140%;}</style>" \ |
|
439 |
+ "</head><body><h2>DIY Radiation Monitor</h2>" \ |
|
440 |
+ "<p><a href=\"http://intravisions.com/radmon/\">" \ |
|
441 |
+ "<i>intravisions.com</i></a></p><hr>" \ |
|
442 |
+ "<p><pre>UTC	")); |
|
443 |
+ /* Data Items */ |
|
445 | 444 |
client.print(strtok(strBuffer, " ")); |
446 | 445 |
client.print(F(" ")); |
447 | 446 |
client.print(strtok(NULL, ", ")); |
448 |
- client.print(F("<BR>")); |
|
447 |
+ client.print(F("<br>")); |
|
449 | 448 |
client.print(strtok(NULL, ", ")); |
450 | 449 |
client.print(F("	")); |
451 | 450 |
client.print(strtok(NULL, ", ")); |
452 |
- client.print(F("<BR>")); |
|
451 |
+ client.print(F("<br>")); |
|
453 | 452 |
client.print(strtok(NULL, ", ")); |
454 | 453 |
client.print(F("	")); |
455 | 454 |
client.print(strtok(NULL, ", ")); |
456 |
- client.print(F("<BR>")); |
|
455 |
+ client.print(F("<br>")); |
|
457 | 456 |
client.print(strtok(NULL, ", ")); |
458 | 457 |
client.print(F("	")); |
459 | 458 |
client.print(strtok(NULL, ", ")); |
460 |
- client.print(F("<BR>")); |
|
459 |
+ client.print(F("<br>")); |
|
461 | 460 |
client.print(F("Mode	")); |
462 | 461 |
client.print(strtok(NULL, ", ")); |
463 |
- client.print(F("<BR></PRE></FONT></BODY></HTML>")); |
|
462 |
+ client.print(F("<br></pre></p></body></html>")); |
|
464 | 463 |
return; |
465 | 464 |
} |
466 | 465 |
|
... | ... |
@@ -475,7 +474,7 @@ void transmitJson(EthernetClient client) { |
475 | 474 |
/* |
476 | 475 |
* Format and transmit a JSON compatible data string. |
477 | 476 |
*/ |
478 |
- client.print(F("[{\"radmon\":\"$,UTC=")); |
|
477 |
+ client.print(F("$,UTC=")); |
|
479 | 478 |
client.print(strtok(strBuffer, " ")); |
480 | 479 |
client.print(F(" ")); |
481 | 480 |
client.print(strtok(NULL, ", ")); |
... | ... |
@@ -494,7 +493,7 @@ void transmitJson(EthernetClient client) { |
494 | 493 |
client.print(F(",")); |
495 | 494 |
client.print(F("Mode=")); |
496 | 495 |
client.print(strtok(NULL, ", ")); |
497 |
- client.print(F(",#,\"}]")); |
|
496 |
+ client.print(F(",#")); |
|
498 | 497 |
return; |
499 | 498 |
} |
500 | 499 |
|
... | ... |
@@ -56,9 +56,11 @@ _HTTP_REQUEST_TIMEOUT = 5 # number seconds to wait for a response to HTTP reques |
56 | 56 |
### GLOBAL VARIABLES ### |
57 | 57 |
|
58 | 58 |
webUpdateInterval = _DEFAULT_WEB_DATA_UPDATE_INTERVAL # web update frequency |
59 |
-deviceUrl = "http://192.168.1.8" # radiation monitor network address |
|
59 |
+deviceUrl = "{your URL}" # radiation monitor network address |
|
60 |
+deviceOnline = True |
|
60 | 61 |
debugOption = False |
61 | 62 |
|
63 |
+ |
|
62 | 64 |
### PRIVATE METHODS ### |
63 | 65 |
|
64 | 66 |
def getTimeStamp(): |
... | ... |
@@ -70,89 +72,97 @@ def getTimeStamp(): |
70 | 72 |
return time.strftime( "%Y/%m/%d %T", time.localtime() ) |
71 | 73 |
##end def |
72 | 74 |
|
73 |
-def sendOffLineStatusMessage(): |
|
74 |
- """Sets the status of the the upstream device to "offline" and sends |
|
75 |
+def setOfflineStatus(dData): |
|
76 |
+ """Set the status of the the upstream device to "offline" and sends |
|
75 | 77 |
blank data to the downstream clients. |
76 |
- Parameters: none |
|
78 |
+ Parameters: |
|
79 |
+ dData - dictionary object containing weather data |
|
77 | 80 |
Returns nothing. |
78 | 81 |
""" |
79 |
- sTmp = "\"date\":\"\",\"CPS\":\"\",\"CPM\":\"\"," \ |
|
80 |
- "\"uSvPerHr\":\"\",\"Mode\":\"\",\"status\":\"offline\"" |
|
81 |
- |
|
82 |
- lsTmp = sTmp.split(',') |
|
83 |
- lsTmp[0] = "\"date\":\"%s\"" % getTimeStamp() |
|
84 |
- writeOutputDataFile(lsTmp) |
|
82 |
+ global deviceOnline |
|
83 |
+ |
|
84 |
+ # If the radiation monitor was previously online, then send a message |
|
85 |
+ # that we are now offline. |
|
86 |
+ if deviceOnline: |
|
87 |
+ print "%s: radmon offline" % getTimeStamp() |
|
88 |
+ deviceOnline = False |
|
89 |
+ |
|
90 |
+ # Set data items to blank. |
|
91 |
+ dData['UTC'] = '' |
|
92 |
+ dData['CPM'] = '' |
|
93 |
+ dData['CPS'] = '' |
|
94 |
+ dData['uSvPerHr'] = '' |
|
95 |
+ dData['Mode'] = '' |
|
96 |
+ dData['status'] = 'offline' |
|
97 |
+ |
|
98 |
+ writeOutputDataFile(dData) |
|
85 | 99 |
return |
86 | 100 |
##end def |
87 | 101 |
|
88 | 102 |
### PUBLIC METHODS ### |
89 | 103 |
|
90 | 104 |
def getRadmonData(deviceUrl, HttpRequestTimeout): |
91 |
- """Send http request to radiation monitoring device. The response |
|
92 |
- from the device contains the radiation data. The data is formatted |
|
93 |
- as an html document. |
|
94 |
- Parameters: |
|
95 |
- deviceUrl - url of radiation monitoring device |
|
96 |
- HttpRequesttimeout - how long to wait for device |
|
97 |
- to respond to http request |
|
98 |
- Returns a string containing the radiation data, or None if |
|
99 |
- not successful. |
|
100 |
- """ |
|
101 |
- content = "" |
|
102 |
- try: |
|
103 |
- conn = urllib2.urlopen(deviceUrl + "/jsdata", timeout=HttpRequestTimeout) |
|
104 |
- except Exception, exError: |
|
105 |
- # If no response is received from the device, then assume that |
|
106 |
- # the device is down or unavailable over the network. In |
|
107 |
- # that case set the status of the device to offline. |
|
108 |
- print "%s: device offline: %s" % \ |
|
109 |
- (getTimeStamp(), exError) |
|
110 |
- return None |
|
111 |
- else: |
|
112 |
- for line in conn: |
|
113 |
- content += line.strip() |
|
114 |
- if len(content) == 0: |
|
115 |
- print "%s: HTTP download failed: null content" % \ |
|
116 |
- (getTimeStamp()) |
|
117 |
- return None |
|
118 |
- del conn |
|
119 |
- return content |
|
105 |
+ """Send http request to radiation monitoring device. The response |
|
106 |
+ from the device contains the radiation data. The data is formatted |
|
107 |
+ as an html document. |
|
108 |
+ Parameters: |
|
109 |
+ deviceUrl - url of radiation monitoring device |
|
110 |
+ HttpRequesttimeout - how long to wait for device |
|
111 |
+ to respond to http request |
|
112 |
+ Returns a string containing the radiation data, or None if |
|
113 |
+ not successful. |
|
114 |
+ """ |
|
115 |
+ global deviceOnline |
|
116 |
+ |
|
117 |
+ try: |
|
118 |
+ conn = urllib2.urlopen(deviceUrl + "/rdata", timeout=HttpRequestTimeout) |
|
119 |
+ except Exception, exError: |
|
120 |
+ # If no response is received from the device, then assume that |
|
121 |
+ # the device is down or unavailable over the network. In |
|
122 |
+ # that case set the status of the device to offline. |
|
123 |
+ if debugOption: |
|
124 |
+ print "getRadmonData: %s\n" % exError |
|
125 |
+ return None |
|
126 |
+ |
|
127 |
+ # If the radiation monitor was previously offline, then send a message |
|
128 |
+ # that we are now online. |
|
129 |
+ if not deviceOnline: |
|
130 |
+ print "%s radmon online" % getTimeStamp() |
|
131 |
+ deviceOnline = True |
|
132 |
+ |
|
133 |
+ # Format received data into a single string. |
|
134 |
+ content = "" |
|
135 |
+ for line in conn: |
|
136 |
+ content += line.strip() |
|
137 |
+ del conn |
|
138 |
+ return content |
|
120 | 139 |
##end def |
121 | 140 |
|
122 |
-def parseDataString(sData, lsData, dData): |
|
141 |
+def parseDataString(sData, dData): |
|
123 | 142 |
"""Parse the radiation data JSON string from the radiation |
124 | 143 |
monitoring device into its component parts. |
125 | 144 |
Parameters: |
126 | 145 |
sData - the string containing the data to be parsed |
127 |
- lsData - a list object to contain the parsed data items |
|
128 | 146 |
dData - a dictionary object to contain the parsed data items |
129 | 147 |
Returns true if successful, false otherwise. |
130 | 148 |
""" |
131 |
- # Clear data array in preparation for loading reformatted data. |
|
132 |
- while len(lsData) > 0: |
|
133 |
- elmt = lsData.pop(0) |
|
134 |
- |
|
135 | 149 |
try: |
136 |
- dTmp = json.loads(sData[1:-1]) |
|
137 |
- sTmp = dTmp['radmon'].encode('ascii', 'ignore') |
|
150 |
+ sTmp = sData[2:-2] |
|
138 | 151 |
lsTmp = sTmp.split(',') |
139 |
- lsData.extend(lsTmp) |
|
140 | 152 |
except Exception, exError: |
141 |
- print "%s parse failed: %s" % (getTimeStamp(), exError) |
|
153 |
+ print "%s parseDataString: %s" % (getTimeStamp(), exError) |
|
142 | 154 |
return False |
143 | 155 |
|
144 |
- # Since the device responded, set the status to online. |
|
145 |
- lsData.insert(-2, "status=online") |
|
146 |
- |
|
147 | 156 |
# Load the parsed data into a dictionary for easy access. |
148 |
- for item in lsData: |
|
157 |
+ for item in lsTmp: |
|
149 | 158 |
if "=" in item: |
150 | 159 |
dData[item.split('=')[0]] = item.split('=')[1] |
160 |
+ dData['status'] = 'online' |
|
151 | 161 |
|
152 | 162 |
return True |
153 | 163 |
##end def |
154 | 164 |
|
155 |
-def convertData(lsData, dData): |
|
165 |
+def convertData(dData): |
|
156 | 166 |
"""Convert individual radiation data items as necessary. |
157 | 167 |
Parameters: |
158 | 168 |
lsData - a list object containing the radiation data |
... | ... |
@@ -166,47 +176,44 @@ def convertData(lsData, dData): |
166 | 176 |
ts_utc = time.strptime(dData['UTC'], "%H:%M:%S %m/%d/%Y") |
167 | 177 |
local_sec = calendar.timegm(ts_utc) |
168 | 178 |
dData['UTC'] = local_sec |
169 |
- except: |
|
170 |
- print "%s invalid time: %s" % (getTimeStamp(), utc) |
|
171 |
- result = False |
|
172 |
- |
|
173 |
- # Clear data array in preparation for loading reformatted data. |
|
174 |
- while len(lsData) > 0: |
|
175 |
- elmt = lsData.pop(0) |
|
176 | 179 |
|
177 |
- lsData.append("\"UTC\":\"%s\"" % dData['UTC']) |
|
178 |
- lsData.append("\"CPS\":\"%s\"" % dData['CPS']) |
|
179 |
- lsData.append("\"CPM\":\"%s\"" % dData['CPM']) |
|
180 |
- lsData.append("\"uSvPerHr\":\"%s\"" % dData['uSv/hr']) |
|
181 |
- lsData.append("\"Mode\":\"%s\"" % dData['Mode'].lower()) |
|
182 |
- lsData.append("\"status\":\"%s\"" % dData['status']) |
|
180 |
+ dData['uSvPerHr'] = dData.pop('uSv/hr') |
|
181 |
+ dData['Mode'] = dData.pop('Mode').lower() |
|
182 |
+ except Exception, exError: |
|
183 |
+ print "%s convertData: %s" % (getTimeStamp(), exError) |
|
184 |
+ result = False |
|
183 | 185 |
|
184 | 186 |
return result |
185 | 187 |
##end def |
186 | 188 |
|
187 |
-def writeOutputDataFile(lsData): |
|
189 |
+def writeOutputDataFile(dData): |
|
188 | 190 |
"""Convert individual weather string data items as necessary. |
189 | 191 |
Parameters: |
190 | 192 |
lsData - a list object containing the data to be written |
191 | 193 |
to the JSON file |
192 | 194 |
Returns true if successful, false otherwise. |
193 | 195 |
""" |
194 |
- # Convert the list object to a string. |
|
195 |
- sTmp = ','.join(lsData) |
|
196 |
+ # Set date to current time and data |
|
197 |
+ dData['date'] = getTimeStamp() |
|
196 | 198 |
|
197 |
- # Apply JSON formatting to the string and write it to a |
|
198 |
- # file for use by html documents. |
|
199 |
- sData = "[{%s}]\n" % (sTmp) |
|
199 |
+ # Format the weather data as string using java script object notation. |
|
200 |
+ sData = '[{' |
|
201 |
+ for key in dData: |
|
202 |
+ sData += "\"%s\":\"%s\"," % (key, dData[key]) |
|
203 |
+ sData = sData[:-1] + '}]\n' |
|
200 | 204 |
|
205 |
+ # Write the string to the output data file for use by html documents. |
|
201 | 206 |
try: |
202 | 207 |
fc = open(_OUTPUT_DATA_FILE, "w") |
203 | 208 |
fc.write(sData) |
204 | 209 |
fc.close() |
205 | 210 |
except Exception, exError: |
206 |
- print "%s: write to JSON file failed: %s" % \ |
|
207 |
- (getTimeStamp(), exError) |
|
211 |
+ print "%s writeOutputDataFile: %s" % (getTimeStamp(), exError) |
|
208 | 212 |
return False |
209 | 213 |
|
214 |
+ if debugOption: |
|
215 |
+ print sData |
|
216 |
+ |
|
210 | 217 |
return True |
211 | 218 |
## end def |
212 | 219 |
|
... | ... |
@@ -220,7 +227,7 @@ def updateDatabase(dData): |
220 | 227 |
Returns true if successful, false otherwise. |
221 | 228 |
""" |
222 | 229 |
# The RR database stores whole units, so convert uSv to Sv. |
223 |
- Svvalue = float(dData['uSv/hr']) * 1.0E-06 # convert micro-Sieverts to Sieverts |
|
230 |
+ Svvalue = float(dData['uSvPerHr']) * 1.0E-06 # convert micro-Sieverts to Sieverts |
|
224 | 231 |
|
225 | 232 |
# Create the rrdtool update command. |
226 | 233 |
strCmd = "rrdtool update %s %s:%s:%s" % \ |
... | ... |
@@ -328,7 +335,7 @@ def main(): |
328 | 335 |
|
329 | 336 |
lastChartUpdateTime = - 1 # last time charts generated |
330 | 337 |
lastDatabaseUpdateTime = -1 # last time the rrdtool database updated |
331 |
- lastWebDataUpdateTime = -1 # last time output JSON file updated |
|
338 |
+ lastWebUpdateTime = -1 # last time output JSON file updated |
|
332 | 339 |
dData = {} # dictionary object for temporary data storage |
333 | 340 |
lsData = [] # list object for temporary data storage |
334 | 341 |
|
... | ... |
@@ -351,28 +358,27 @@ def main(): |
351 | 358 |
|
352 | 359 |
# At the radiation device query interval request and process |
353 | 360 |
# the data from the device. |
354 |
- if currentTime - lastWebDataUpdateTime > webUpdateInterval: |
|
355 |
- llastWebDataUpdateTime = currentTime |
|
361 |
+ if currentTime - lastWebUpdateTime > webUpdateInterval: |
|
362 |
+ lastWebUpdateTime = currentTime |
|
356 | 363 |
result = True |
357 | 364 |
|
358 | 365 |
# Get the data string from the device. |
359 | 366 |
sData = getRadmonData(deviceUrl, _HTTP_REQUEST_TIMEOUT) |
360 | 367 |
if sData == None: |
361 |
- sendOffLineStatusMessage() |
|
368 |
+ setOfflineStatus(dData) |
|
362 | 369 |
result = False |
363 | 370 |
|
364 | 371 |
# If successful parse the data. |
365 | 372 |
if result: |
366 |
- result = parseDataString(sData, lsData, dData) |
|
373 |
+ result = parseDataString(sData, dData) |
|
367 | 374 |
|
368 | 375 |
# If parsing successful, convert the data. |
369 | 376 |
if result: |
370 |
- result = convertData(lsData, dData) |
|
377 |
+ result = convertData(dData) |
|
371 | 378 |
|
372 | 379 |
# If conversion successful, write data to output file. |
373 | 380 |
if result: |
374 |
- lsData[0] = "\"date\":\"%s\"" % getTimeStamp() |
|
375 |
- writeOutputDataFile(lsData) |
|
381 |
+ writeOutputDataFile(dData) |
|
376 | 382 |
|
377 | 383 |
# At the rrdtool database update interval, update the database. |
378 | 384 |
if currentTime - lastDatabaseUpdateTime > _DATABASE_UPDATE_INTERVAL: |