Last active
December 18, 2015 13:39
-
-
Save industrialinternet/5791668 to your computer and use it in GitHub Desktop.
TX_AprilDigital_Out_SCADA
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a bit of fun to show how device and sensor state is typical displayed on commercial SCADA | |
// systems used in manufacturing, process control and electricity grid control rooms. | |
// But using the Electric imp and HTML5 | |
//Imp & Agent are written in squirrel-lang.org They should have a .NUT extension. | |
//but I've used .js so the editor will use colour highlighting. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Tx April Digital Outputs SCADA screen | |
const ON=1 | |
const OFF=0 | |
// Array that holds the state of each pin | |
pinState <- [ 0, 0, 0, 0, 0, 0]; | |
// Pins array channel 1 is channelPin[0] in array | |
local Pins = [ hardware.pin1, hardware.pin2, hardware.pin5, hardware.pin7, hardware.pin8, hardware.pin9 ]; | |
// Register imp | |
imp.configure("T3: April SCADA Tank",[],[]); | |
server.log("T3: April SCADA - v1.0"); | |
// Event handler for state changes | |
function pinEvent() | |
{ | |
// Idle for 50ms to allow switch to settle | |
imp.sleep(0.05); | |
// Read each switch | |
for(local _pin=0; _pin<2; _pin++) | |
{ | |
// Get switch state | |
local state = Pins[_pin].read(); | |
// State changed? | |
if(state != pinState[_pin]) | |
{ | |
// Update pin sate | |
pinState[_pin] = state; | |
} | |
} | |
// send pin state to Agent | |
agent.send("impValues",{pin1=pinState[0],pin2=pinState[1],rssi=imp.rssi(),vdd=hardware.voltage(),bssid=imp.getbssid(),mac=imp.getmacaddress()}); | |
} | |
agent.on("setOutputs", function(agentMSG) { | |
if("v1_op" in agentMSG){ | |
server.log("v1_op:"+agentMSG.v1_op); | |
Pins[2].write(agentMSG.v1_op=="on" ? ON : OFF); | |
} | |
if("v2_op" in agentMSG) { | |
server.log("v2_op:"+agentMSG.v2_op); | |
Pins[3].write(agentMSG.v2_op=="on" ? ON : OFF); | |
} | |
if(Pins[2].read() ==0 && Pins[3].read() ==1){ | |
server.log("Pump On!"); | |
Pins[0].write(ON); | |
agent.send("impValues",{p1_op=ON,v1_op=Pins[2].read(),v2_op=Pins[3].read(),rssi=imp.rssi(),vdd=hardware.voltage(),bssid=imp.getbssid(),mac=imp.getmacaddress()}); | |
} else { | |
server.log("Pump Off!"); | |
Pins[0].write(OFF); | |
agent.send("impValues",{p1_op=OFF,v1_op=Pins[2].read(),v2_op=Pins[3].read(),rssi=imp.rssi(),vdd=hardware.voltage(),bssid=imp.getbssid(),mac=imp.getmacaddress()}); | |
} | |
server.log("v1:"+Pins[2].read()+" v2:"+Pins[3].read()); | |
}); | |
// Configure input pins with internal pull-up | |
Pins[0].configure(DIGITAL_OUT); | |
Pins[0].write(OFF); | |
Pins[1].configure(DIGITAL_IN_PULLUP, pinEvent); | |
Pins[2].configure(DIGITAL_OUT); | |
Pins[2].write(OFF); | |
Pins[3].configure(DIGITAL_OUT); | |
Pins[3].write(OFF); | |
agent.send("impValues",{p1_op=pinState[0],v1_op=Pins[2].read(),v2_op=Pins[3].read(),rssi=imp.rssi(),vdd=hardware.voltage(),bssid=imp.getbssid(),mac=imp.getmacaddress()}); | |
try { | |
server.log(imp.getsoftwareversion()); | |
} catch(error) { | |
server.log("old version! "+error); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Tx April Digital Outputs SCADA screen | |
server.log("Agent: start SCADA Tank v1.0"); | |
_p1_op <- ""; | |
_v1_op <- ""; | |
_v2_op <- ""; | |
_tmp <- ""; | |
_rh <- ""; | |
_rssi <-""; | |
_vdd <-""; | |
_bssid <-""; | |
_mac <-""; | |
function sendIMPvalues(request,res){ | |
//res.header("Access-Control-Allow-Origin", "*"); | |
res.header("Access-Control-Allow-Origin", "http://industrialinternet.co.uk"); | |
// server.log("reqMethod:"+request.method); | |
if(request.method=="GET"){ | |
local vars = { | |
"p1_op": ""+_p1_op+"", | |
"v1_op": ""+_v1_op+"", | |
"v2_op": ""+_v2_op+"", | |
"rssi": ""+_rssi+"", | |
"vdd": ""+_vdd+"" | |
"bssid": ""+_bssid+"", | |
"mac": ""+_mac+"" | |
} | |
local jvars = http.jsonencode(vars); | |
res.send(200,jvars); | |
} | |
if(request.method=="OPTIONS"){ | |
res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); | |
res.header("Access-Control-Allow-Headers", "origin, x-csrftoken, content-type, accept"); | |
res.send(200,"OK.OPTIONS"); | |
} | |
if(request.method=="POST"){ | |
local impAction = http.jsondecode(request.body); | |
if(("v1_op" in impAction) || ("v2_op" in impAction)){ | |
device.send("setOutputs", impAction); | |
res.header("AgentResponce", "Pin_Request_OK"); | |
} else { | |
res.header("AgentResponce", "Pin_Request_Error"); | |
} | |
res.header("Access-Control-Expose-Headers", "AgentResponce"); | |
res.send(200,"OK.POST"); | |
} | |
} | |
// When HTTP request comes in handel with sendIMPvalues | |
http.onrequest(sendIMPvalues); | |
// Process msg from imp | |
device.on("impValues",function(iv){ | |
server.log("agent: impValues:"+iv.p1_op+":"+iv.v1_op+":"+iv.v2_op+":"+iv.rssi+":"+iv.vdd+":"+iv.bssid+":"+iv.mac); | |
_p1_op = iv.p1_op; | |
_v1_op = iv.v1_op; | |
_v2_op = iv.v2_op; | |
_rssi = iv.rssi; | |
_vdd = iv.vdd; | |
_bssid = iv.bssid; | |
_mac = iv.mac; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="Pragma" content="no-cache"> | |
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | |
<title>SCADA </title> | |
<link rel="stylesheet" type="text/css" href="css/ScreenBGs/simpleControls.css" /> | |
<style> | |
#ScreenBG {float: left; width:600px; height:450px; margin:25px 5px 10px 40px; padding:3px 0 0 0px; background:#FFFFFF url(css/ScreenBGs/tanks.png) 0 0 no-repeat;} | |
#Header { float: left; height:20px; width:100%; margin:0px; padding:10px; border-left: 0px solid #CF0B4F; background:#cccccc; } | |
#v1 {position: absolute; top:70px; left:50px;} | |
#v2 {position: absolute; top:354px; left:308px;} | |
#p1 {position: absolute; top:354px; left:228px;} | |
#C4 {position: absolute; top:95px; left:170px;} | |
#C5 {position: absolute; top:180px; left:37px;} | |
#C6 {position: absolute; top:180px; left:208px;} | |
#tank2 {position: absolute; top:140px; left:112px;} | |
a {text-decoration:none;} | |
</style> | |
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" /> | |
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> | |
<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script> | |
<script> | |
var polling = false; | |
var agentActions = ""; | |
var empty = false; | |
var fill = false; | |
var level = 100; | |
var pumpState = ""; | |
var reFill=false; | |
var fillLevel =-15; | |
var full= true; | |
var emptyLevel = 25; | |
$( function() { | |
function emptyTank(_tank,ts,_height){ | |
var canvas=document.getElementById(_tank); | |
if(!canvas.getContext){return;} | |
var ctx=canvas.getContext('2d'); | |
_ht=_height*ts; | |
_yp=130-_ht; | |
console.info("level:"+level+" height:"+_height); | |
level--; | |
ctx.fillStyle='#FFF'; | |
//ctx.fillRect(0, _yp, 300, 120 ); | |
ctx.fillRect(0, _height, 300, 3 ); | |
} | |
function reFillTank(_tank,ts,_height){ | |
if($("#v1").attr('class')=='valveOff') return; | |
if(_height>=100) return; | |
var canvas=document.getElementById(_tank); | |
if(!canvas.getContext){return;} | |
var ctx=canvas.getContext('2d'); | |
_ht=_height*ts; | |
_yp=130-_ht; | |
console.info("yp:"+_yp+" level:"+level+" height:"+_height); | |
level++; | |
ctx.fillStyle='#9CCEE0'; | |
ctx.fillRect(0, _yp, 300, 120 ); | |
} | |
var externalURL ="jK7Apk642eUv"; | |
var pollRate ="1000"; | |
// Send switch state to Agent | |
function postToIMP(){ | |
if(polling == true){ | |
console.log("delay post @2"); | |
$(function(){ | |
setTimeout(postToIMP, 100); | |
}); | |
} else { | |
polling = true; | |
$.ajax({ | |
type: "POST", | |
url: "https://agent.electricimp.com/"+externalURL, | |
data: agentActions, | |
contentType: "application/json; charset=utf-8", | |
dataType: "json", | |
complete: function(jqXHR, textStatus){ | |
_header= jqXHR.getResponseHeader("AgentResponce"); | |
console.log("textStatus: "+jqXHR.responseText+" AgentResponce:"+_header); | |
polling = false; | |
} | |
}); | |
} | |
} | |
//Work out which switch has been clicked | |
function impSetValue(_pin,_slider_value){ | |
var jobj = {_pin : _slider_value } | |
var jobj = { _pin : _slider_value }; | |
var obj = {}; | |
pinID = ""+_pin+""; | |
obj[pinID] = _slider_value; | |
agentActions = JSON.stringify(obj); | |
console.log("agentActions:"+ agentActions); | |
if(polling == true){ | |
console.log("delay post @1"); | |
//var _delay = setTimeout((function(){postToIMP}),100); | |
$(function(){ | |
setTimeout(postToIMP, 100); | |
}); | |
} else { | |
postToIMP(); | |
} | |
} | |
function poll(){ | |
if(polling == true) return; | |
if (empty){ // Empty tank when pump runs | |
emptyLevel++; | |
emptyTank('tank2',1,emptyLevel); | |
} | |
if(reFill){ // Slowely fill tank when pump stops | |
fillLevel++; | |
reFillTank('tank2',1,fillLevel); | |
} | |
polling = true; | |
$.ajax({ | |
type: "get", | |
url: "https://agent.electricimp.com/"+externalURL, | |
dataType: "json", | |
success: function(agentMsg) { | |
updatePump("#p1",agentMsg.p1_op); | |
updateValve("#v1",agentMsg.v1_op); | |
updateValve("#v2",agentMsg.v2_op); | |
polling = false; | |
}, | |
error: function(err) { | |
console.log("err"+ err.status) | |
} | |
}); | |
} | |
// Set the rate to poll your imp | |
setInterval(function(){ poll(); }, pollRate); | |
// Update pump icon based on imp output | |
function updatePump(cid,_value){ | |
//console.log("cid:"+cid+" _value:"+_value); | |
if(pumpState == _value) return; | |
if( _value == "1"){ | |
$(cid).attr('class','pumpOn'); | |
empty = true; | |
reFill = false; | |
} else { | |
$(cid).attr('class','pumpOff'); | |
empty = false; | |
reFill = true; | |
} | |
pumpState = _value; | |
} | |
// Update pump icon based on imp output | |
function updateValve(cid,_value){ | |
//console.log("cid:"+cid+" _value:"+_value); | |
if( _value == "1"){ | |
$(cid).attr('class','valveOn'); | |
} else { | |
$(cid).attr('class','valveOff'); | |
} | |
} | |
$("[data-role=slider]").bind( "change", function(event, ui) { | |
var slider_value = $(this).slider().val(); | |
_vid = this.id.split("_"); | |
vid ="#"+_vid[0]; | |
_c=$(vid).attr('class'); | |
isValve=_c.lastIndexOf("valve"); | |
_vs = _c =="valveOff" ? "valveOn" : "valveOff"; | |
$(vid).attr('class',_vs); | |
console.log(_vid[0],_c,slider_value,_vs+" : valve? "+isValve); | |
impSetValue(this.id,slider_value); | |
}); | |
function updateToggle(did,_value){ | |
console.log("did"+did+" v"+_value); | |
var _switch = $(did); | |
if( _value == "1"){ | |
_switch[0].selectedIndex = 1; | |
_switch.slider("refresh"); | |
} else { | |
_switch[0].selectedIndex = 0; | |
_switch.slider("refresh"); | |
} | |
} | |
$("[data-role=popup]").bind( "popupafteropen", function(event, ui) { | |
_cid = this.id.split("_"); | |
cid ="#"+_cid[0]; | |
_c=$(cid).attr('class'); | |
if(_c.charAt(0)=="v"){ | |
_cs = _c =="valveOff" ? "0" : "1"; | |
_cpop = cid+"_op"; | |
updateToggle(_cpop,_cs); | |
} | |
console.log(this.id+"pop bind"); | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
<div data-role="page" style="background: #FFFFFF;"> | |
<div id="Header">SCADA sceen with Electric imp | |
</div> | |
<div id="ScreenBG"> | |
<div id="v1" class="valveOff" title="V1: line 1 tank feed"> | |
<a id="v1pop" href="#v1_popup" data-rel="popup" data-position-to="origin" data-transition="pop">V1</a> | |
</div> | |
<div id="p1" class="pumpOff" title="P1: outlet line feed pump"> | |
<a id="p1pop" href="#p1_popup" data-rel="popup" data-position-to="origin" data-transition="pop">P1</a> | |
</div> | |
<div id="v2" class="valveOff" title="V2: line 1 process feed"> | |
<a id="v2pop" href="#v2_popup" data-rel="popup" data-position-to="origin" data-transition="pop">V2</a> | |
</div> | |
<canvas id="tank2" style="width:129px; height:151px; border:0px solid red; margin:1px 0 0 4px"></canvas> | |
</div> | |
<!-- popups --> | |
<div data-role="popup" id="v1_popup" style="padding-left:10px;"> | |
<a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-btn-left">Close</a> | |
<div data-role="fieldcontain" style="width:180px;"><!-- Toggle switches --> | |
<h3>Open/Close valve</h3> | |
<label for="v1_op" style="padding-left:5px;">v1</label> | |
<select id="v1_op" data-role="slider"> | |
<option value="off">Off</option> | |
<option value="on">On</option> | |
</select> | |
</div> | |
</div> | |
<div data-role="popup" id="v2_popup" style="padding-left:10px;"> | |
<a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-btn-left">Close</a> | |
<div data-role="fieldcontain" style="width:180px;"><!-- Toggle switches --> | |
<h3>Open/Close valve</h3> | |
<label for="v2_op" style="padding-left:5px;">v2</label> | |
<select id="v2_op" data-role="slider"> | |
<option value="off">Off</option> | |
<option value="on">On</option> | |
</select> | |
</div> | |
</div> | |
</div> | |
</div> <!-- Eof page --> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment