Skip to content

Instantly share code, notes, and snippets.

@industrialinternet
Last active December 18, 2015 13:39
Show Gist options
  • Save industrialinternet/5791668 to your computer and use it in GitHub Desktop.
Save industrialinternet/5791668 to your computer and use it in GitHub Desktop.
TX_AprilDigital_Out_SCADA
// 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.
//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);
}
//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;
});
<!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