Commit 299e5fbe authored by nextime's avatar nextime

Add tables and support for syncing board configs in daemon

parent 6295d491
CREATE TABLE IF NOT EXISTS `ioconf_analogs` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`boardname` varchar(255) NOT NULL,
`boardip` varchar(15) NOT NULL,
`ananum` smallint(6) NOT NULL DEFAULT '1',
`status_num` enum('1','2','3','4') NOT NULL DEFAULT '1',
`status_name` varchar(32) NOT NULL DEFAULT 'DEFAULT',
`enabled` enum('yes','no') NOT NULL DEFAULT 'no',
`anatype` int(5) unsigned NOT NULL DEFAULT '0',
`mintime` int(5) unsigned NOT NULL DEFAULT '1',
`minval` int(11) NOT NULL DEFAULT '0',
`maxval` int(11) NOT NULL DEFAULT '1023',
`continuos_domain` varchar(32) NOT NULL,
`continuos_msg` int(5) unsigned NOT NULL DEFAULT '0',
`continuos_ctx` int(5) unsigned NOT NULL DEFAULT '0',
`continuos_act` int(5) unsigned NOT NULL DEFAULT '0',
`continuos_time` int(6) NOT NULL DEFAULT '1',
`continuos_opt` int(5) unsigned NOT NULL DEFAULT '0',
`continuos_optstring` varchar(64) NOT NULL,
`continuos_dst` varchar(15) NOT NULL DEFAULT '0.0.0.0',
`min_domain` varchar(32) NOT NULL,
`min_msg` int(5) unsigned NOT NULL DEFAULT '0',
`min_ctx` int(5) unsigned NOT NULL DEFAULT '0',
`min_act` int(5) unsigned NOT NULL DEFAULT '0',
`min_level` int(6) NOT NULL DEFAULT '1',
`min_opt` int(5) unsigned NOT NULL DEFAULT '0',
`min_optstring` varchar(64) NOT NULL,
`min_dst` varchar(15) NOT NULL DEFAULT '0.0.0.0',
`max_domain` varchar(32) NOT NULL,
`max_msg` int(5) unsigned NOT NULL DEFAULT '0',
`max_ctx` int(5) unsigned NOT NULL DEFAULT '0',
`max_act` int(5) unsigned NOT NULL DEFAULT '0',
`max_level` int(6) NOT NULL DEFAULT '1',
`max_opt` int(5) unsigned NOT NULL DEFAULT '0',
`max_optstring` varchar(64) NOT NULL,
`max_dst` varchar(15) NOT NULL DEFAULT '0.0.0.0',
PRIMARY KEY (`id`),
KEY `enables` (`enabled`),
KEY `boardname` (`boardname`),
KEY `boardip` (`boardip`),
KEY `status_num` (`status_num`),
KEY `status_name` (`status_name`),
KEY `anatype` (`anatype`),
KEY `ananum` (`ananum`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `ioconf_inputs` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`boardname` varchar(255) NOT NULL,
`boardip` varchar(15) NOT NULL,
`inpnum` smallint(6) NOT NULL DEFAULT '0',
`status_num` enum('1','2','3','4') NOT NULL DEFAULT '1',
`status_name` varchar(32) NOT NULL DEFAULT 'DEFAULT',
`enabled` enum('yes','no') NOT NULL DEFAULT 'no',
`inptype` int(5) unsigned NOT NULL DEFAULT '0',
`mintime` int(5) unsigned NOT NULL DEFAULT '1',
`act1_domain` varchar(32) NOT NULL,
`act1_msg` int(5) unsigned NOT NULL DEFAULT '0',
`act1_ctx` int(5) unsigned NOT NULL DEFAULT '0',
`act1_act` int(5) unsigned NOT NULL DEFAULT '0',
`act1_time` int(6) NOT NULL DEFAULT '1',
`act1_opt` int(5) unsigned NOT NULL DEFAULT '0',
`act1_optstring` varchar(64) NOT NULL,
`act1_dst` varchar(15) NOT NULL DEFAULT '0.0.0.0',
`act2_domain` varchar(32) NOT NULL,
`act2_msg` int(5) unsigned NOT NULL DEFAULT '0',
`act2_ctx` int(5) unsigned NOT NULL DEFAULT '0',
`act2_act` int(5) unsigned NOT NULL DEFAULT '0',
`act2_level` int(6) NOT NULL DEFAULT '1',
`act2_opt` int(5) unsigned NOT NULL DEFAULT '0',
`act2_optstring` varchar(64) NOT NULL,
`act2_dst` varchar(15) NOT NULL DEFAULT '0.0.0.0',
`act3_domain` varchar(32) NOT NULL,
`act3_msg` int(5) unsigned NOT NULL DEFAULT '0',
`act3_ctx` int(5) unsigned NOT NULL DEFAULT '0',
`act3_act` int(5) unsigned NOT NULL DEFAULT '0',
`act3_level` int(6) NOT NULL DEFAULT '1',
`act3_opt` int(5) unsigned NOT NULL DEFAULT '0',
`act3_optstring` varchar(64) NOT NULL,
`act3_dst` varchar(15) NOT NULL DEFAULT '0.0.0.0',
PRIMARY KEY (`id`),
KEY `enables` (`enabled`),
KEY `boardname` (`boardname`),
KEY `boardip` (`boardip`),
KEY `status_num` (`status_num`),
KEY `status_name` (`status_name`),
KEY `anatype` (`inptype`),
KEY `inpnum` (`inpnum`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `ioconf_outputs` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`boardname` varchar(255) NOT NULL,
`boardip` varchar(15) NOT NULL,
`outnum` smallint(6) NOT NULL DEFAULT '0',
`enabled` enum('yes','no') NOT NULL DEFAULT 'no',
`outtype` int(5) unsigned NOT NULL DEFAULT '0',
`ctx` int(5) unsigned NOT NULL DEFAULT '0',
`startime` int(5) unsigned NOT NULL DEFAULT '50',
`opentime` int(5) unsigned NOT NULL DEFAULT '300',
`pausetime` int(5) NOT NULL DEFAULT '50',
`bang` enum('yes','no') NOT NULL DEFAULT 'no',
`r1_relay` int(5) unsigned NOT NULL DEFAULT '0',
`r1_def` enum('NC','NO','SAVE') NOT NULL DEFAULT 'NO',
`r1_duration` int(5) unsigned NOT NULL DEFAULT '0',
`r1_retard` int(5) unsigned NOT NULL DEFAULT '0',
`r1_tollerance` int(5) unsigned NOT NULL DEFAULT '0',
`r1_rearm` int(5) unsigned NOT NULL DEFAULT '0',
`r1_ampere` int(3) unsigned NOT NULL DEFAULT '80',
`r2_relay` int(5) unsigned NOT NULL DEFAULT '0',
`r2_def` enum('NC','NO','SAVE') NOT NULL DEFAULT 'NO',
`r2_duration` int(5) unsigned NOT NULL DEFAULT '0',
`r2_retard` int(5) unsigned NOT NULL DEFAULT '0',
`r2_tollerance` int(5) unsigned NOT NULL DEFAULT '0',
`r2_rearm` int(5) unsigned NOT NULL DEFAULT '0',
`r2_ampere` int(3) unsigned NOT NULL DEFAULT '80',
PRIMARY KEY (`id`),
KEY `enables` (`enabled`),
KEY `boardname` (`boardname`),
KEY `boardip` (`boardip`),
KEY `anatype` (`outtype`),
KEY `outnum` (`outnum`),
KEY `ctx` (`ctx`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `ioconf_pwm` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
...@@ -30,7 +30,10 @@ ...@@ -30,7 +30,10 @@
<div class="panel col-lg-4"> <div class="panel col-lg-4">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title">Boards <a data-toggle="modal" href="#AutoDetect" class="btn btn-danger btn-small pull-right" style="padding:3px;">Autodetect</a></h3> <h3 class="panel-title">Boards
<a data-toggle="modal" data-dmboard="lock" href="#AutoDetect" class="btn btn-danger btn-small pull-right" style="padding:3px;margin-left:5px;">Autodetect</a>
<a data-toggle="modal" data-dmboard="lock" href="#Sync" class="btn btn-danger btn-small pull-right" style="padding:3px;">Sync I/O Config</a>
</h3>
</div> </div>
<div class="home-panel"> <div class="home-panel">
<table class="table table-condensed"> <table class="table table-condensed">
...@@ -55,6 +58,14 @@ ...@@ -55,6 +58,14 @@
<td><?=$board['type']?></td> <td><?=$board['type']?></td>
<td><?=$board['fwversion']?></td> <td><?=$board['fwversion']?></td>
<td><?=$board['fwtype']?></td> <td><?=$board['fwtype']?></td>
<td>
<!--
<button style="margin-left:5px;" type="button" class="btn btn-success btn-small pull-right">Edit</button>
-->
<button style="margin-left:5px;" type="button" data-dmact="sync" data-boardid="<?=$board['id']?>" class="btn btn-danger btn-small pull-right">Sync</button>
<button style="margin-left:5px;" type="button" data-dmact="push" data-boardid="<?=$board['id']?>" class="btn btn-info btn-small pull-right">Push</button>
<img src="/resources/preloader/images/animated.gif" data-dmboardload="<?=$board['id']?>" style="height:30px;width:30px;display:none" class="pull-right"></img>
</td>
</tr> </tr>
<? <?
} }
...@@ -86,6 +97,27 @@ ...@@ -86,6 +97,27 @@
</div><!-- /.modal-dialog --> </div><!-- /.modal-dialog -->
</div><!-- /.modal --> </div><!-- /.modal -->
<div class="modal fade" id="Sync" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Board IOConf Sync</h4>
</div>
<div class="modal-body">
<b>WARNING: </b>you are starting Domotika Boards I/O Sync procedure. This will
delete any saved board I/O Config in the Domotika database and then
they will be re-loaded from the Domotika boards.
Any change will be losed.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" >Discard</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" id="startsync">Start Syncing</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="panel col-lg-4"> <div class="panel col-lg-4">
<div class="panel-heading"> <div class="panel-heading">
...@@ -213,6 +245,39 @@ ...@@ -213,6 +245,39 @@
</div> <!-- container --> </div> <!-- container -->
<?include("parts/foot.php");?> <?include("parts/foot.php");?>
<script type="text/javascript"> <script type="text/javascript">
function lockGlobalBoards()
{
$("[data-dmboard=lock]").each(
function(){
$(this).attr("disabled","true");
}
);
}
function lockAllBoards()
{
$("[data-dmact=sync]").each(
function(){
$(this).attr("disabled","true");
}
);
$("[data-dmact=push]").each(
function(){
$(this).attr("disabled","true");
}
);
$("[data-dmboardload]").each(
function(){
$(this).css("display","block");
}
);
lockGlobalBoards();
}
$("#startdetection").click( $("#startdetection").click(
function() { function() {
if($('#forcedetect').is(":checked")) if($('#forcedetect').is(":checked"))
...@@ -221,6 +286,49 @@ ...@@ -221,6 +286,49 @@
$.get("/rest/v1.2/boards/autodetect/json"); $.get("/rest/v1.2/boards/autodetect/json");
} }
); );
$("#startsync").click(
function() {
lockAllBoards();
$.get("/rest/v1.2/boards/syncall/json");
}
);
$("[data-dmact=push]").click(
function() {
$("[data-dmboardload="+$(this).attr('data-boardid')+"]").each(
function(){
$(this).css("display","block");
}
);
$(this).attr('disabled', true);
$("[data-dmact=sync][data-boardid="+$(this).attr('data-boardid')+"]").each(
function() {
$(this).attr('disabled', true);
}
);
lockGlobalBoards();
$.get("/rest/v1.2/boards/pushboardbyid/"+$(this).attr('data-boardid')+"/json");
}
)
$("[data-dmact=sync]").click(
function() {
$("[data-dmboardload="+$(this).attr('data-boardid')+"]").each(
function(){
$(this).css("display","block");
}
);
$(this).attr('disabled', true);
$("[data-dmact=push][data-boardid="+$(this).attr('data-boardid')+"]").each(
function() {
$(this).attr('disabled', true);
}
);
lockGlobalBoards();
$.get("/rest/v1.2/boards/syncboardbyid/"+$(this).attr('data-boardid')+"/json");
}
)
</script> </script>
</body> </body>
</html> </html>
...@@ -24,7 +24,37 @@ ...@@ -24,7 +24,37 @@
} }
var unlockBoards = function(event) {
var data=$.parseJSON(event.data);
$("[data-dmact=sync][data-boardid="+data.data+"],[data-dmact=push][data-boardid="+data.data+"]").each(
function() {
$(this).attr("disabled", false);
}
);
$("[data-dmboardload="+data.data+"]").each(
function(){
$(this).css("display","none");
}
);
var loaders=false;
$("[data-dmboardload]").each(
function(){
if($(this).css("display")=="block")
loaders=true;
}
);
if(loaders==false)
{
$("[data-dmboard=lock]").each(
function(){
$(this).attr("disabled",false);
}
);
}
}
es.addEventListener("daemonstatus", setDaemonStatus); es.addEventListener("daemonstatus", setDaemonStatus);
es.addEventListener("boardOK", unlockBoards);
es.onerror = function(event){ es.onerror = function(event){
if(es.readystate=='CLOSED') if(es.readystate=='CLOSED')
......
...@@ -31,7 +31,12 @@ from dmlib import constants as C ...@@ -31,7 +31,12 @@ from dmlib import constants as C
from twisted.web import microdom as xml from twisted.web import microdom as xml
from domotika.lang import lang from domotika.lang import lang
from iotype import BoardAnalog, BoardInput, BoardOutput, BoardRelay from iotype import BoardAnalog, BoardInput, BoardOutput, BoardRelay
from twisted.web import error
from dmlib.utils.pwgen import GeneratePwd
from dmlib.utils import genutils
from twisted.internet import reactor
from domotika.db import dmdb
import urllib
log = logging.getLogger( 'Core' ) log = logging.getLogger( 'Core' )
...@@ -45,6 +50,41 @@ except: ...@@ -45,6 +50,41 @@ except:
import sha1 import sha1
# i_[idx]_[ananum+totinp]_[statusnum]_[act]
ANAINDEX={
'status_name': ['09', '00'],
'enabled': ['05', '00'],
'anatype': ['11', '00'],
'mintime': ['06', '00'],
'minval': ['12', '00'],
'maxval': ['13', '00'],
'continuos_domain': ['02','01'],
'continuos_msg': ['07','01'],
'continuos_ctx': ['03','01'],
'continuos_act': ['01','01'],
'continuos_time': ['10','01'],
'continuos_opt': ['14','01'],
'continuos_optstring': ['15','01'],
'continuos_dst': ['04','01'],
'min_domain': ['02','02'],
'min_msg': ['07','02'],
'min_ctx': ['03','02'],
'min_act': ['01','02'],
'min_level': ['10','02'],
'min_opt': ['14','02'],
'min_optstring': ['15','02'],
'min_dst': ['04','02'],
'max_domain': ['02','03'],
'max_msg': ['07','03'],
'max_ctx': ['03','03'],
'max_act': ['01','03'],
'max_level': ['10','03'],
'max_opt': ['14','03'],
'max_optstring': ['15','03'],
'max_dst': ['04','03'],
}
def context2section(ctx): def context2section(ctx):
if int(ctx) in C.SECTIONS.keys(): if int(ctx) in C.SECTIONS.keys():
section=C.SECTIONS[int(ctx)] section=C.SECTIONS[int(ctx)]
...@@ -74,7 +114,14 @@ class BaseBoard(object): ...@@ -74,7 +114,14 @@ class BaseBoard(object):
numAna = 2 numAna = 2
numInp = 12 numInp = 12
numOut = 12 numOut = 12
initialized = False
boardid = False
analogLock = False
inputLock = False
outputLock = False
pwmLock = False
def __init__(self, core, host, port, pwd, lang): def __init__(self, core, host, port, pwd, lang):
#self.fwtype = 'relaymaster' #self.fwtype = 'relaymaster'
self.host = host self.host = host
...@@ -83,13 +130,35 @@ class BaseBoard(object): ...@@ -83,13 +130,35 @@ class BaseBoard(object):
self.lang = lang self.lang = lang
self.core = core self.core = core
def endinit(self, res):
self.initialized=True
return res
def initialize(self): def initialize(self):
d=self._getBoardConfig() d=self._getBoardConfig()
d.addCallback(self._setBoardConfig) d.addCallback(self._setBoardConfig)
d.addCallback(self._getIOConfig) d.addCallback(self._getIOConfig)
d.addCallback(self._setIOConfig) d.addCallback(self._setIOConfig)
d.addCallback(self._configComplete) d.addCallback(self._configComplete)
return d return d.addCallback(self.endinit)
def sendUnLock(self):
def _send(res):
if res:
return self.core.boardOK(res.id)
if (not self.analogLock
and not self.inputLock
and not self.outputLock
and not self.pwmLock):
boardname=str(xml.getElementsByTagName(self.boardXML, 'cfg_hostname')[0].firstChild().toxml())
boardip=str(xml.getElementsByTagName(self.boardXML, 'cfg_ip')[0].firstChild().toxml())
log.info("Unlocking board module "+str(boardname)+" at "+str(boardip))
if not self.boardid:
return dmdb.DMBoards.find(where=["name='%s' and ip='%s'" %(boardname, boardip)], limit=1).addCallback(_send)
return self.core.boardOK(boardid)
def _configComplete(self, *a): def _configComplete(self, *a):
return defer.succeed(self) return defer.succeed(self)
...@@ -111,8 +180,34 @@ class BaseBoard(object): ...@@ -111,8 +180,34 @@ class BaseBoard(object):
def _getIOConfig(self, *a): def _getIOConfig(self, *a):
return self.requestPage("http://"+self.host+":"+str(self.port)+"/ioconf.xml") return self.requestPage("http://"+self.host+":"+str(self.port)+"/ioconf.xml")
def requestPage(self, uri): def _requestPageErr(self, err, uri=False, method='GET', postdata=None, nolocation=False, second=False):
return wu.getPage(uri, http_user=self.user, http_password=self.pwd) if err.getErrorMessage().split()[0] == '401' and not second:
log.info('Board '+str(self.host)+' doesn\'t appears to support SETOTP command for uri '+str(uri))
return wu.getPage(uri, http_user=self.user, http_password=self.pwd,
method=method, postdata=postdata).addErrback(self._requestPageErr, uri, nolocation=nolocation, second=True)
log.error("Page "+str(uri)+"can't be accessed! ("+err.getErrorMessage()+")")
raise error.Error(err.getErrorMessage().split()[0], err.getErrorMessage())
def _requestPageOk(self, res, uri):
log.info('Board '+str(self.host)+' OTP Request OK for uri '+str(uri))
return res
def _requestOTPPage(self, uri, pwd, method='GET', postdata=None, nolocation=False):
log.info("Send OTP Request for "+str(uri)+" with pwd "+str(pwd))
return wu.getPage(uri, http_user='otp', http_password=str(pwd), method=method, postdata=postdata, nolocation=nolocation
).addCallback(self._requestPageOk, uri
).addErrback(self._requestPageErr, uri, method, postdata, nolocation)
def _requestPage(self, res, uri, pwd, method='GET', postdata=None, nolocation=False):
return self._requestOTPPage(uri, pwd, method, postdata, nolocation)
def requestPage(self, uri, method='GET', postdata=None, nolocation=False):
pwd=GeneratePwd(leng=16)
self.core.setOTP(pwd, self.host)
d=defer.Deferred()
d.addCallback(self._requestPage, uri, pwd, method, postdata, nolocation)
reactor.callLater(.5, d.callback, True)
return d
def getAnalogsNames(self): def getAnalogsNames(self):
return {} return {}
...@@ -145,9 +240,139 @@ class ANABoard(object): ...@@ -145,9 +240,139 @@ class ANABoard(object):
return ret return ret
return self.analist return self.analist
def syncAnalogs(self):
if self.analogLock:
return
self.analogLock=True
if not self.initialized:
self.initialize().addCallback(
self._ioAnalogsDelete).addCallback(
self._syncAnalogs)
else:
self._ioAnalogsDelete().addCallback(
self._syncAnalogs)
def _ioAnalogsDelete(self, res=None):
boardname=str(xml.getElementsByTagName(self.boardXML, 'cfg_hostname')[0].firstChild().toxml())
boardip=str(xml.getElementsByTagName(self.boardXML, 'cfg_ip')[0].firstChild().toxml())
return dmdb.runOperation("DELETE FROM ioconf_analogs WHERE boardname='%s' AND boardip='%s'" %(str(boardname), str(boardip)))
def _syncAnalogs(self, res=None):
boardname=str(xml.getElementsByTagName(self.boardXML, 'cfg_hostname')[0].firstChild().toxml())
boardip=str(xml.getElementsByTagName(self.boardXML, 'cfg_ip')[0].firstChild().toxml())
log.info("Syncing board "+str(boardname)+" at "+str(boardip))
for i in [self.firstAna, self.firstAna+self.numAna-1]:
aname=xml.getElementsByTagName(self.ioXML, 'i'+str(i))[0].firstChild().toxml()
for n in xrange(1, 5):
sconf=str(xml.getElementsByTagName(self.ioXML, 'i'+str(i)+'s'+str(n))[0].firstChild().toxml()).split(';')
d=dmdb.IOConfAnalogs()
d.boardname=boardname
d.boardip=boardip
d.ananum=i-self.firstAna+1
d.status_num=n
d.status_name=sconf[0]
d.enabled='yes' if sconf[2]=='1' else 'no'
d.anatype=int(sconf[3])
d.mintime=int(sconf[1])
d.minval=int(sconf[28])
d.maxval=int(sconf[29])
d.continuos_domain=str(sconf[4])
d.continuos_msg=int(sconf[8])
d.continuos_ctx=int(sconf[7])
d.continuos_act=int(sconf[9])
d.continuos_time=int(sconf[6])
d.continuos_opt=int(sconf[10])
d.continuos_optstring=str(sconf[11])
d.continuos_dst=str(sconf[5])
d.min_domain=str(sconf[12])
d.min_msg=int(sconf[16])
d.min_ctx=int(sconf[15])
d.min_act=int(sconf[17])
d.min_level=int(sconf[14])
d.min_opt=int(sconf[18])
d.min_optstring=str(sconf[19])
d.min_dst=str(sconf[13])
d.max_domain=str(sconf[20])
d.max_msg=int(sconf[24])
d.max_ctx=int(sconf[23])
d.max_act=int(sconf[25])
d.max_level=int(sconf[22])
d.max_opt=int(sconf[26])
d.max_optstring=str(sconf[27])
d.max_dst=str(sconf[21])
d.save()
self.analogLock=False
self.sendUnLock()
def pushAnalogs(self, ananum=False, status='*', dataonly=False, bname=False):
if self.analogLock:
return
if genutils.is_number(status) and int(status) in [1,2,3,4]:
s=int(status)
else:
s=str(status)
if not ananum or ananum=='*':
self._pushAnalog(1, s, dataonly, bname).addCallback(lambda x: self._pushAnalog(2, s, dataonly, bname))
else:
if genutils.is_number(ananum) and int(ananum) in [1,2]:
self._pushAnalog(int(ananum), s, dataonly, bname)
def _sendAnalogIOConf(self, res, dataonly=False):
def endPush(res):
log.info("Push for "+str(uri)+" finished")
self.analogLock=False
self.sendUnLock()
return defer.succeed(True)
def normalize(v):
if v in ['yes','no']:
return '1' if v=='yes' else '0'
return urllib.quote(str(a[k]))
postdata=""
for ana in res:
if dataonly:
if type(dataonly).__name__!='list':
dataonly=str(dataonly).replace(" ","").split(",")
else:
dataonly=ANAINDEX.keys()
a=ana.__dict__
for k in dataonly:
if k in a.keys():
if len(postdata)>0:
postdata+="&"
postdata+="i_"+ANAINDEX[k][0]+"_"+str(a['ananum']+self.firstAna-1).zfill(2)+"_"
postdata+=str(a['status_num']).zfill(2)+"_"+ANAINDEX[k][1]+"="
postdata+=normalize(a[k])
uri="http://"+self.host+":"+str(self.port)+"/ioconf.xml"
log.info("Posting Analog config to "+str(uri))
return self.requestPage(uri, method='POST', postdata=postdata, nolocation=True).addCallbacks(endPush, endPush)
def _getAnalogIOConf(self, res, num, status, dataonly=False, bname=False):
boardname=bname
boardip=self.host
if not bname:
boardname=str(xml.getElementsByTagName(self.boardXML, 'cfg_hostname')[0].firstChild().toxml())
#sqlstring="SELECT * FROM ioconf_analogs WHERE boardname='%s' AND boardip='%s'" % (boardname, boardip)
sqlstring="boardname='%s' AND boardip='%s'" % (boardname, boardip)
if genutils.is_number(status) and status != '*':
sqlstring+=" AND status_num='%s'" % str(status)
elif status!='*':
sqlstring+=" AND DMDOMAIN(status, '%s')=1"
#dmdb.runQuery(sqlstring).addCallback(self._sendAnalogIOConf, dataonly)
return dmdb.IOConfAnalogs.find(where=[sqlstring]).addCallback(self._sendAnalogIOConf, dataonly)
def _pushAnalog(self, num, status, dataonly=False, bname=False):
self.analogLock=True
if not bname and not self.initialized:
return self.initialize().addCallback(self._getAnalogIOConf, num, status, dataonly, bname)
return self._getAnalogIOConf(True, num, status, dataonly, bname)
class INPBoard(object): class INPBoard(object):
def getInputsNames(self): def getInputsNames(self):
if not self.inplist: if not self.inplist:
ret = {} ret = {}
...@@ -164,6 +389,12 @@ class INPBoard(object): ...@@ -164,6 +389,12 @@ class INPBoard(object):
return ret return ret
return self.inplist return self.inplist
def syncInputs(self):
pass
def pushInputs(self, inpnum=False, status=1):
pass
class OUTBoard(object): class OUTBoard(object):
...@@ -295,3 +526,8 @@ class OUTBoard(object): ...@@ -295,3 +526,8 @@ class OUTBoard(object):
self.outlist = ret self.outlist = ret
return self.outlist return self.outlist
def syncOutputs(self):
pass
def pushOutputs(self, numout=False):
pass
...@@ -106,6 +106,18 @@ def dbset(): ...@@ -106,6 +106,18 @@ def dbset():
global store global store
Registry.DBPOOL = store Registry.DBPOOL = store
class IOConfInputs(DBObject):
TABLENAME="ioconf_inputs"
class IOConfAnalogs(DBObject):
TABLENAME="ioconf_analogs"
class IOConfOutput(DBObject):
TABLENAME="ioconf_outputs"
class IOConfPwm(DBObject):
TABLENAME="ioconf_pwm"
class Analog(DBObject): class Analog(DBObject):
TABLENAME="analog" TABLENAME="analog"
...@@ -224,6 +236,8 @@ class StatsData(DBObject): ...@@ -224,6 +236,8 @@ class StatsData(DBObject):
class StatsHistory(DBObject): class StatsHistory(DBObject):
TABLENAME="stats_history" TABLENAME="stats_history"
def cleanFlags(): def cleanFlags():
Registry.getConfig().delete("flags", where=["expire<="+str(time.time())]) Registry.getConfig().delete("flags", where=["expire<="+str(time.time())])
......
...@@ -467,6 +467,41 @@ class domotikaService(service.Service): ...@@ -467,6 +467,41 @@ class domotikaService(service.Service):
self.upnp_detected_ips=[] self.upnp_detected_ips=[]
return dmdb.resetDynMediaSources() return dmdb.resetDynMediaSources()
def _syncBoards(self, res): # XXX Make which i/o/a is synced selectively
if res:
for b in res:
p=pluggableBoards.getBoardPlugin(b.type, ConvenienceCaller(lambda c: self._callback('board', c)))
if b:
pboard = p.getBoard(b.ip, b.webport, self.boardsyspwd, str(self.config.get('general', 'language')))
pboard.syncAnalogs()
pboard.syncInputs()
pboard.syncOutputs()
#pboard.syncPwm()
return True
def syncBoards(self, bid=False, *a, **kw):
if not bid:
return dmdb.DMBoards.find(where=['online=1']).addCallback(self._syncBoards)
return dmdb.DMBoards.find(where=['online=1 and id="%s"' % str(bid)]).addCallback(self._syncBoards)
def _pushBoards(self, res): # XXX Make which i/o/a is pushed selectively
if res:
for b in res:
p=pluggableBoards.getBoardPlugin(b.type, ConvenienceCaller(lambda c: self._callback('board', c)))
if b:
pboard = p.getBoard(b.ip, b.webport, self.boardsyspwd, str(self.config.get('general', 'language')))
pboard.pushAnalogs()
pboard.pushInputs()
pboard.pushOutputs()
#pboard.pushPwm()
return True
def pushBoards(self, bid=False, *a, **kw):
if not bid:
return dmdb.DMBoards.find(where=['online=1']).addCallback(self._pushBoards)
return dmdb.DMBoards.find(where=['online=1 and id="%s"' % str(bid)]).addCallback(self._pushBoards)
def autoDetectBoards(self, *a, **kw): def autoDetectBoards(self, *a, **kw):
log.info("Start building boardlist") log.info("Start building boardlist")
...@@ -592,12 +627,15 @@ class domotikaService(service.Service): ...@@ -592,12 +627,15 @@ class domotikaService(service.Service):
dmdb.Analog.find(where=["""ananum=? AND board_name=? """, a.num, name ]).addCallback(self.insertAnalog, dmdb.Analog.find(where=["""ananum=? AND board_name=? """, a.num, name ]).addCallback(self.insertAnalog,
a, name, fwver a, name, fwver
) )
bplugin.syncAnalogs()
if bplugin.hasInputs: if bplugin.hasInputs:
for i in bplugin.getInputsNames().values(): for i in bplugin.getInputsNames().values():
dmdb.Input.find(where=["""inpnum=? AND board_name=? """, i.num, name]).addCallback(self.insertInput, dmdb.Input.find(where=["""inpnum=? AND board_name=? """, i.num, name]).addCallback(self.insertInput,
i, name, fwver i, name, fwver
) )
bplugin.syncInputs()
if bplugin.hasOutputs: if bplugin.hasOutputs:
for o in bplugin.getOutputsConfs().values(): for o in bplugin.getOutputsConfs().values():
# OUTPUT NOTE: is based on output not on relay! an output can have more than 1 relay... # OUTPUT NOTE: is based on output not on relay! an output can have more than 1 relay...
...@@ -607,6 +645,7 @@ class domotikaService(service.Service): ...@@ -607,6 +645,7 @@ class domotikaService(service.Service):
dmdb.Output.find(where=["""outnum=? AND board_name=? """, i, name]).addCallback(self.insertOutput, dmdb.Output.find(where=["""outnum=? AND board_name=? """, i, name]).addCallback(self.insertOutput,
o, name, fwver o, name, fwver
) )
bplugin.syncOutputs()
def insertOutput(self, res, out, name, fwver): def insertOutput(self, res, out, name, fwver):
...@@ -767,7 +806,7 @@ class domotikaService(service.Service): ...@@ -767,7 +806,7 @@ class domotikaService(service.Service):
def addBoard(self, btype, fwver, name, ip, webport=80, ptype='UDP4', port=6654): def addBoard(self, btype, fwver, name, ip, webport=80, ptype='UDP4', port=6654):
log.debug(" ".join(["ADDBoard", str(name), str(btype), str(fwver), str(ip)])) log.debug(" ".join(["ADDBoard", str(name), str(btype), str(fwver), str(ip)]))
p=pluggableBoards.getBoardPlugin(btype) p=pluggableBoards.getBoardPlugin(btype, ConvenienceCaller(lambda c: self._callback('board', c)))
if p: if p:
pboard = p.getBoard(ip, webport, self.boardsyspwd, str(self.config.get('general', 'language'))) pboard = p.getBoard(ip, webport, self.boardsyspwd, str(self.config.get('general', 'language')))
log.info("Support module for "+str(btype)+" board LOADED") log.info("Support module for "+str(btype)+" board LOADED")
...@@ -911,6 +950,21 @@ class domotikaService(service.Service): ...@@ -911,6 +950,21 @@ class domotikaService(service.Service):
except: except:
pass pass
def ioConfig(what, act, who, **args):
what = what.lower()
act = act.lower()
if what=='analog':
if act=='setlimits':
maxval=False
minval=False
status='DEFAULT'
if 'max' in args.keys() and genutils.is_number(args['max']):
maxval=int(args['max'])
if 'min' in args.keys() and genutils.is_number(args['min']):
minval=int(args['min'])
if 'status' in args.keys():
status=args['status']
def executeAction(self, command): def executeAction(self, command):
def multipleInsertNotify(dbres, nsrc, expire, msg): def multipleInsertNotify(dbres, nsrc, expire, msg):
if dbres: if dbres:
...@@ -924,6 +978,20 @@ class domotikaService(service.Service): ...@@ -924,6 +978,20 @@ class domotikaService(service.Service):
subprocess.Popen( subprocess.Popen(
command.replace("\r\n", " "), command.replace("\r\n", " "),
shell=True, preexec_fn = os.setsid) shell=True, preexec_fn = os.setsid)
elif command.startswith("IOCONF ") or command.startswith("IOCONF:"):
command=command[7:]
if ':' in command:
cl=command.split(':')
else:
cl=command.split()
if len(cl)>=3:
what=cl[0]
act=cl[1]
who=cl[2]
if len(cl)>3:
self.ioConfig(what, act, who, **dict([i.split('=') for i in cl[3:] if '=' in i and len(i.split('='))>1 and i.split('=')[1]]))
else:
self.ioConfig(what, act, who)
elif command.startswith("NETSTATUS ") or command.startswith("NETSTATUS:"): elif command.startswith("NETSTATUS ") or command.startswith("NETSTATUS:"):
command=command[10:] command=command[10:]
nst=command.split()[0] nst=command.split()[0]
...@@ -2113,6 +2181,12 @@ class domotikaService(service.Service): ...@@ -2113,6 +2181,12 @@ class domotikaService(service.Service):
self.autoDetectBoards() self.autoDetectBoards()
return self.daemonstatus return self.daemonstatus
def web_on_startSync(self, bid=False):
return self.syncBoards(bid=bid)
def web_on_startPush(self, bid=False):
return self.pushBoards(bid=bid)
def web_on_getAuth(self, usr, pwd): def web_on_getAuth(self, usr, pwd):
return dmdb.Users.find(where=["username='%s' AND passwd='%s' AND active=1" % ( usr, pwd)]) return dmdb.Users.find(where=["username='%s' AND passwd='%s' AND active=1" % ( usr, pwd)])
...@@ -2415,4 +2489,10 @@ class domotikaService(service.Service): ...@@ -2415,4 +2489,10 @@ class domotikaService(service.Service):
def fagi_on_voiceReceived(self, txt, confidence=0.0, lang="it"): def fagi_on_voiceReceived(self, txt, confidence=0.0, lang="it"):
return self.voiceRecognized(txt,confidence,lang,voicesrc='VoIP') return self.voiceRecognized(txt,confidence,lang,voicesrc='VoIP')
def board_on_setOTP(self, pwd, ipdst):
log.info('SETOTP for '+str(ipdst)+' ('+str(pwd)+')')
self.sendCommand('SETOTP'+str(pwd), msgtype=C.IKAP_MSG_ACTION, ctx=C.IKAP_CTX_SYSTEM, act=C.IKAP_ACT_BOARD, ipdst=ipdst)
return defer.succeed(True)
def board_on_boardOK(self, bid):
self.clientSend('boardOK', bid)
...@@ -312,6 +312,24 @@ class BoardRest(RestCore): ...@@ -312,6 +312,24 @@ class BoardRest(RestCore):
self.core.startAutoDetection(True) self.core.startAutoDetection(True)
ResponseConversion(request, entity='OK') ResponseConversion(request, entity='OK')
@route("/syncall")
@wrapResponse
def boardForceAutodetect(self, request, *a, **kw):
self.core.startSync()
ResponseConversion(request, entity='OK')
@route("/syncboardbyid/<int:boardid>")
@wrapResponse
def syncBoardById(self, request, boardid):
self.core.startSync(boardid)
ResponseConversion(request, entity='OK')
@route("/pushboardbyid/<int:boardid>")
@wrapResponse
def pushBoardById(self, request, boardid):
self.core.startPush(boardid)
ResponseConversion(request, entity='OK')
class CronRest(RestCore): class CronRest(RestCore):
......
#!/bin/bash
cd `dirname $0`
./boardcmd.py $1 BOOTLOAD 0.0.0.0 eth0 ./boardcmd.py $1 BOOTLOAD 0.0.0.0 eth0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment