Add some different xPL implementations done by Telldus
This commit is contained in:
parent
deebf2045e
commit
d4b46c71ec
21 changed files with 2285 additions and 0 deletions
371
xpl/data/uml.xmi
Normal file
371
xpl/data/uml.xmi
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<XMI verified="false" xmi.version="1.2" timestamp="2009-08-20T21:13:04" xmlns:UML="http://schema.omg.org/spec/UML/1.3" >
|
||||||
|
<XMI.header>
|
||||||
|
<XMI.documentation>
|
||||||
|
<XMI.exporter>umbrello uml modeller http://uml.sf.net</XMI.exporter>
|
||||||
|
<XMI.exporterVersion>1.5.8</XMI.exporterVersion>
|
||||||
|
<XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
|
||||||
|
</XMI.documentation>
|
||||||
|
<XMI.metamodel xmi.version="1.3" href="UML.xml" xmi.name="UML" />
|
||||||
|
</XMI.header>
|
||||||
|
<XMI.content>
|
||||||
|
<UML:Model isSpecification="false" isAbstract="false" isLeaf="false" xmi.id="m1" isRoot="false" name="UML Model" >
|
||||||
|
<UML:Namespace.ownedElement>
|
||||||
|
<UML:Stereotype visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="folder" name="folder" />
|
||||||
|
<UML:Stereotype visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="datatype" name="datatype" />
|
||||||
|
<UML:Stereotype visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="enum" name="enum" />
|
||||||
|
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Logical View" name="Logical View" >
|
||||||
|
<UML:Namespace.ownedElement>
|
||||||
|
<UML:Package stereotype="folder" visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Datatypes" name="Datatypes" >
|
||||||
|
<UML:Namespace.ownedElement>
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="IGSdGv66Dl0t" name="int" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="U4XSIE3QJ6hx" name="char" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="wqDoP5wfLOIc" name="bool" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="HMiS7gMcit21" name="float" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="63PN95L5vWtI" name="double" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="bnxw9DWQZCtg" name="short" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="sDGZ4IaALxYS" name="long" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="2rVxNPDwAAqK" name="unsigned int" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="NNkuXbbOmpxp" name="unsigned short" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="8XzRUVsXMNSh" name="unsigned long" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="kedvoSFAnx4K" name="string" />
|
||||||
|
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" elementReference="dvT79RUD0eZq" isRoot="false" xmi.id="blfxn9Uuu2yR" name="Map<string, string>" />
|
||||||
|
</UML:Namespace.ownedElement>
|
||||||
|
</UML:Package>
|
||||||
|
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="XdiJTf8ZA6yd" name="xPLMessage" >
|
||||||
|
<UML:Classifier.feature>
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="Oy4sMfnqmwFE" type="blfxn9Uuu2yR" name="body" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="7Dsh3RQhMBqr" type="IGSdGv66Dl0t" name="hop" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="o7d2CrsruJHZ" type="kedvoSFAnx4K" name="source" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="fRQUU8LUIdpp" type="kedvoSFAnx4K" name="target" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="tCGUEQs0VW0i" type="ZqAwEabwEDr1" name="identifier" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="HHoVQbGDrTVa" type="kedvoSFAnx4K" name="messageSchemeIdentifier" />
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="IvRClCZ1LX9n" name="xPLMessage" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="fqxUu37A4RS3" type="ZqAwEabwEDr1" value="" name="identifier" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="uUirWhfMjnAf" name="addBodyItem" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="5UmJmRq4exRu" type="kedvoSFAnx4K" value="" name="key" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="gUweefMhDcVo" type="kedvoSFAnx4K" value="" name="value" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Ujr3jkVCgowi" name="addHeadItem" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="M6EhfsocNMwl" type="kedvoSFAnx4K" value="" name="key" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="vB79kv7SfBkB" type="kedvoSFAnx4K" value="" name="value" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Zvm4WIb2Z2yx" name="bodyItem" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="rqKcz5n6oSXF" type="kedvoSFAnx4K" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="0U12xzu7s4bX" name="setMessageSchemeIdentifier" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="0baZghhFr2Gt" type="ZqAwEabwEDr1" value="" name="msi" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="IjmpHLdfT2KV" name="setSource" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="rmmDgsIsGvAe" type="kedvoSFAnx4K" value="" name="value" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="5F2P6cAAbBHb" name="setTarget" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="SpoO35A5dPta" type="kedvoSFAnx4K" value="" name="value" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="rfXl2OnJiltE" name="source" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="WAMYNo0vYq2M" type="kedvoSFAnx4K" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="qZIqOH4DSRXm" name="target" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="w1rngMZgkKzR" type="kedvoSFAnx4K" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="tM3YAlRVdQgs" name="toString" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="5XkHvMEmhb5n" type="kedvoSFAnx4K" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" ownerScope="classifier" isRoot="false" xmi.id="MKlnQwQyMUPk" name="createMessageFromString" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="dHW4EsYbaZuh" type="XdiJTf8ZA6yd" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="ZN62oiIzXjU7" type="kedvoSFAnx4K" value="" name="message" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
</UML:Classifier.feature>
|
||||||
|
</UML:Class>
|
||||||
|
<UML:Enumeration stereotype="enum" visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ZqAwEabwEDr1" name="Identifier" >
|
||||||
|
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ZqAwEabwEDr1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="a2Smc4ipHYou" name="xpl-cmnd" />
|
||||||
|
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ZqAwEabwEDr1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="gnMEpp0PriC6" name="xpl-stat" />
|
||||||
|
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ZqAwEabwEDr1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="R3WGxP4bAOpz" name="xpl-trig" />
|
||||||
|
</UML:Enumeration>
|
||||||
|
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="dvT79RUD0eZq" name="Map" />
|
||||||
|
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="4xTqfjoBSIIy" name="xPLInstance" >
|
||||||
|
<UML:Classifier.feature>
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="gzfxVRaEH2yu" type="EhAjKT6PpPv2" name="thisDevice" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="6hYNhUIrbCdr" type="EhAjKT6PpPv2" name="devices[]" />
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ijPzFRB6xmeW" name="xPLInstance" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="CHVlflsSjf9B" type="EhAjKT6PpPv2" value="" name="device" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="QBcO7FmfSSb5" name="xPLInstance" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="RTrVOEMT27QK" type="kedvoSFAnx4K" value="" name="vendor" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="pZAPjjbo64Jc" type="kedvoSFAnx4K" value="" name="device" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="wveG7Ynvnhnk" name="attatched" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="luTzkEVhEVCS" type="wqDoP5wfLOIc" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="6ZLoecJsWISz" name="detach" />
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="G2jy7qV2pA4v" name="devices" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="3jSGxUztZpPb" type="EhAjKT6PpPv2" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="lFdgofbt1M6S" name="sendMessage" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="hnmruig0iw66" type="XdiJTf8ZA6yd" value="" name="message" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="protected" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="bCE0DS6qC5QW" name="attatchedToNetwork" />
|
||||||
|
<UML:Operation visibility="protected" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="moaxEeoRjCxr" name="handleMessage" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="LD8G4G2pzErD" type="wqDoP5wfLOIc" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="9V85HisHjStJ" type="XdiJTf8ZA6yd" value="" name="message" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
</UML:Classifier.feature>
|
||||||
|
</UML:Class>
|
||||||
|
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="EhAjKT6PpPv2" name="xPLDevice" >
|
||||||
|
<UML:Classifier.feature>
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="5LzeZ6f1a24e" type="kedvoSFAnx4K" name="vendor" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="r7p70tyF8bH0" type="kedvoSFAnx4K" name="device" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="gvkX0lhPYP5H" type="kedvoSFAnx4K" name="instance" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="sawPoTW1GCXN" type="kedvoSFAnx4K" name="address" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="st4NSOrILO1a" type="IGSdGv66Dl0t" name="heartbeatInterval" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="1PNIBOyUoUUx" type="IGSdGv66Dl0t" name="port" />
|
||||||
|
<UML:Attribute visibility="private" isSpecification="false" xmi.id="jU2f3VMLHg33" type="P9JIMGtNBq3k" name="lastHeartBeat" />
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="uHpYNKyBWovy" name="xPLDevice" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="qRHXZ0q35DqS" type="kedvoSFAnx4K" value="" name="vendor" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="8soItGDA5jYO" type="kedvoSFAnx4K" value="" name="device" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="ihuWcqZSIoyr" type="kedvoSFAnx4K" value="" name="instance" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="pmsszjK7Z9NS" name="xPLDevice" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="NYbQI7oymhSN" type="kedvoSFAnx4K" value="" name="vendor" />
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="X1nnnldaVVSU" type="kedvoSFAnx4K" value="" name="device" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="rxv2JOVkHT5S" name="address" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="6sTypq4ddy6C" type="kedvoSFAnx4K" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="gowBqombL9ae" name="heartBeatInterval" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="gim7k4LmGj6g" type="IGSdGv66Dl0t" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="1HoixgmuU10N" name="deviceName" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="PL0k7PSvf2Gm" type="kedvoSFAnx4K" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="BIvEFJyCZGpO" name="lastHeartBeat" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="56bP90wqKGUp" type="P9JIMGtNBq3k" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="CUdVuyok5Btg" name="port" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter kind="return" xmi.id="lWuymn7SufRD" type="IGSdGv66Dl0t" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="4RXtnfpZOlly" name="setAddress" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="1MJSZetHX46j" type="kedvoSFAnx4K" value="" name="address" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="jDamtEfHNoSK" name="setHeartBeatInterval" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="MSTbJJwgWBKp" type="IGSdGv66Dl0t" value="" name="minutes" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="la9uc1o3SziP" name="setLastHeartbeat" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="PEdHSGRODs9y" type="P9JIMGtNBq3k" value="" name="timestamp" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="nQWXNeQsFSEb" name="setPort" >
|
||||||
|
<UML:BehavioralFeature.parameter>
|
||||||
|
<UML:Parameter visibility="private" isSpecification="false" xmi.id="z1XnDSALsQqX" type="IGSdGv66Dl0t" value="" name="port" />
|
||||||
|
</UML:BehavioralFeature.parameter>
|
||||||
|
</UML:Operation>
|
||||||
|
</UML:Classifier.feature>
|
||||||
|
</UML:Class>
|
||||||
|
<UML:Enumeration stereotype="enum" visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ioL5YhpoYAWd" name="OperationMode" >
|
||||||
|
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ioL5YhpoYAWd" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="7C7bDTwbQv2H" name="Client" />
|
||||||
|
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ioL5YhpoYAWd" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="DQHpEraw64eW" name="Disconnected" />
|
||||||
|
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ioL5YhpoYAWd" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="MsihEUMf7fjn" name="Hub" />
|
||||||
|
</UML:Enumeration>
|
||||||
|
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="P9JIMGtNBq3k" name="datetime" />
|
||||||
|
</UML:Namespace.ownedElement>
|
||||||
|
<XMI.extension xmi.extender="umbrello" >
|
||||||
|
<diagrams>
|
||||||
|
<diagram showopsig="1" linecolor="#ff0000" snapx="10" showattribassocs="1" snapy="10" linewidth="0" showattsig="1" showpubliconly="0" showpackage="1" showstereotype="1" name="class diagram" font="Sans Serif,10,-1,0,50,0,0,0,0,0" canvasheight="801" canvaswidth="1075" localid="" snapcsgrid="0" showgrid="0" showops="1" usefillcolor="1" fillcolor="#ffff00" zoom="100" xmi.id="hb855HgsAFsZ" documentation="" showscope="1" snapgrid="0" showatts="1" type="1" >
|
||||||
|
<widgets>
|
||||||
|
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="1" x="86" showattsigs="601" showstereotype="1" y="55" showattributes="1" font="Sans Serif,10,-1,5,75,0,0,0,0,0" width="401" isinstance="0" usefillcolor="1" fillcolor="#ffff00" xmi.id="XdiJTf8ZA6yd" showscope="1" height="288" showopsigs="601" />
|
||||||
|
<enumwidget width="79" showstereotype="1" x="546" y="54" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="80" linecolor="none" xmi.id="ZqAwEabwEDr1" showpackage="1" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,0,50,0,0,0,0,0" />
|
||||||
|
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="1" x="106" showattsigs="601" showstereotype="1" y="380" showattributes="1" font="Sans Serif,10,-1,5,75,0,0,0,0,0" width="324" isinstance="0" usefillcolor="1" fillcolor="#ffff00" xmi.id="4xTqfjoBSIIy" showscope="1" height="176" showopsigs="601" />
|
||||||
|
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="1" x="529" showattsigs="601" showstereotype="1" y="180" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="399" isinstance="0" usefillcolor="1" fillcolor="#ffff00" xmi.id="EhAjKT6PpPv2" showscope="1" height="304" showopsigs="601" />
|
||||||
|
</widgets>
|
||||||
|
<messages/>
|
||||||
|
<associations>
|
||||||
|
<assocwidget indexa="1" indexb="1" visibilityA="0" widgetaid="XdiJTf8ZA6yd" visibilityB="0" linecolor="none" changeabilityA="900" totalcounta="2" xmi.id="tCGUEQs0VW0i" changeabilityB="900" widgetbid="ZqAwEabwEDr1" totalcountb="2" type="510" linewidth="none" >
|
||||||
|
<linepath>
|
||||||
|
<startpoint startx="487" starty="115" />
|
||||||
|
<endpoint endx="546" endy="115" />
|
||||||
|
</linepath>
|
||||||
|
<floatingtext linecolor="none" usesdiagramfillcolor="1" linewidth="none" usesdiagramusefillcolor="1" x="482" showstereotype="1" y="117" text="identifier" font="Sans Serif,10,-1,0,50,0,0,0,0,0" pretext="-" role="710" width="66" isinstance="0" posttext="" usefillcolor="1" fillcolor="none" xmi.id="NcywuLejcB4E" height="22" />
|
||||||
|
</assocwidget>
|
||||||
|
<assocwidget indexa="1" indexb="1" visibilityA="0" widgetaid="4xTqfjoBSIIy" visibilityB="0" linecolor="none" changeabilityA="900" totalcounta="3" xmi.id="gzfxVRaEH2yu" changeabilityB="900" widgetbid="EhAjKT6PpPv2" totalcountb="3" type="510" linewidth="none" >
|
||||||
|
<linepath>
|
||||||
|
<startpoint startx="430" starty="432" />
|
||||||
|
<endpoint endx="529" endy="432" />
|
||||||
|
</linepath>
|
||||||
|
<floatingtext linecolor="none" usesdiagramfillcolor="1" linewidth="none" usesdiagramusefillcolor="1" x="452" showstereotype="1" y="400" text="thisDevice" font="Sans Serif,10,-1,0,50,0,0,0,0,0" pretext="-" role="710" width="77" isinstance="0" posttext="" usefillcolor="1" fillcolor="none" xmi.id="dUkwuSZTB6bL" height="22" />
|
||||||
|
</assocwidget>
|
||||||
|
<assocwidget indexa="2" indexb="2" visibilityA="0" widgetaid="4xTqfjoBSIIy" visibilityB="0" linecolor="none" changeabilityA="900" totalcounta="3" xmi.id="6hYNhUIrbCdr" changeabilityB="900" widgetbid="EhAjKT6PpPv2" totalcountb="3" type="510" linewidth="none" >
|
||||||
|
<linepath>
|
||||||
|
<startpoint startx="430" starty="432" />
|
||||||
|
<endpoint endx="529" endy="432" />
|
||||||
|
</linepath>
|
||||||
|
<floatingtext linecolor="none" usesdiagramfillcolor="1" linewidth="none" usesdiagramusefillcolor="1" x="459" showstereotype="1" y="434" text="devices[]" font="Sans Serif,10,-1,0,50,0,0,0,0,0" pretext="-" role="710" width="68" isinstance="0" posttext="" usefillcolor="1" fillcolor="none" xmi.id="QBvCzLeKycFq" height="22" />
|
||||||
|
</assocwidget>
|
||||||
|
</associations>
|
||||||
|
</diagram>
|
||||||
|
</diagrams>
|
||||||
|
</XMI.extension>
|
||||||
|
</UML:Model>
|
||||||
|
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Use Case View" name="Use Case View" >
|
||||||
|
<UML:Namespace.ownedElement/>
|
||||||
|
</UML:Model>
|
||||||
|
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Component View" name="Component View" >
|
||||||
|
<UML:Namespace.ownedElement/>
|
||||||
|
</UML:Model>
|
||||||
|
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Deployment View" name="Deployment View" >
|
||||||
|
<UML:Namespace.ownedElement/>
|
||||||
|
</UML:Model>
|
||||||
|
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Entity Relationship Model" name="Entity Relationship Model" >
|
||||||
|
<UML:Namespace.ownedElement/>
|
||||||
|
</UML:Model>
|
||||||
|
</UML:Namespace.ownedElement>
|
||||||
|
</UML:Model>
|
||||||
|
</XMI.content>
|
||||||
|
<XMI.extensions xmi.extender="umbrello" >
|
||||||
|
<docsettings viewid="hb855HgsAFsZ" uniqueid="w1rngMZgkKzR" documentation="" />
|
||||||
|
<listview>
|
||||||
|
<listitem open="1" type="800" label="Views" >
|
||||||
|
<listitem open="1" type="801" id="Logical View" >
|
||||||
|
<listitem open="0" type="807" id="hb855HgsAFsZ" label="class diagram" />
|
||||||
|
<listitem open="1" type="813" id="dvT79RUD0eZq" />
|
||||||
|
<listitem open="1" type="813" id="P9JIMGtNBq3k" />
|
||||||
|
<listitem open="1" type="813" id="EhAjKT6PpPv2" >
|
||||||
|
<listitem open="0" type="814" id="5LzeZ6f1a24e" />
|
||||||
|
<listitem open="0" type="814" id="r7p70tyF8bH0" />
|
||||||
|
<listitem open="0" type="814" id="gvkX0lhPYP5H" />
|
||||||
|
<listitem open="0" type="814" id="sawPoTW1GCXN" />
|
||||||
|
<listitem open="0" type="814" id="st4NSOrILO1a" />
|
||||||
|
<listitem open="0" type="814" id="1PNIBOyUoUUx" />
|
||||||
|
<listitem open="0" type="814" id="jU2f3VMLHg33" />
|
||||||
|
<listitem open="0" type="815" id="uHpYNKyBWovy" />
|
||||||
|
<listitem open="0" type="815" id="pmsszjK7Z9NS" />
|
||||||
|
<listitem open="0" type="815" id="rxv2JOVkHT5S" />
|
||||||
|
<listitem open="0" type="815" id="gowBqombL9ae" />
|
||||||
|
<listitem open="0" type="815" id="1HoixgmuU10N" />
|
||||||
|
<listitem open="0" type="815" id="BIvEFJyCZGpO" />
|
||||||
|
<listitem open="0" type="815" id="CUdVuyok5Btg" />
|
||||||
|
<listitem open="0" type="815" id="4RXtnfpZOlly" />
|
||||||
|
<listitem open="0" type="815" id="jDamtEfHNoSK" />
|
||||||
|
<listitem open="0" type="815" id="la9uc1o3SziP" />
|
||||||
|
<listitem open="0" type="815" id="nQWXNeQsFSEb" />
|
||||||
|
</listitem>
|
||||||
|
<listitem open="1" type="813" id="4xTqfjoBSIIy" >
|
||||||
|
<listitem open="0" type="814" id="gzfxVRaEH2yu" />
|
||||||
|
<listitem open="0" type="814" id="6hYNhUIrbCdr" />
|
||||||
|
<listitem open="0" type="815" id="ijPzFRB6xmeW" />
|
||||||
|
<listitem open="0" type="815" id="QBcO7FmfSSb5" />
|
||||||
|
<listitem open="0" type="815" id="wveG7Ynvnhnk" />
|
||||||
|
<listitem open="0" type="815" id="6ZLoecJsWISz" />
|
||||||
|
<listitem open="0" type="815" id="G2jy7qV2pA4v" />
|
||||||
|
<listitem open="0" type="815" id="lFdgofbt1M6S" />
|
||||||
|
<listitem open="0" type="815" id="bCE0DS6qC5QW" />
|
||||||
|
<listitem open="0" type="815" id="moaxEeoRjCxr" />
|
||||||
|
</listitem>
|
||||||
|
<listitem open="1" type="813" id="XdiJTf8ZA6yd" >
|
||||||
|
<listitem open="0" type="814" id="Oy4sMfnqmwFE" />
|
||||||
|
<listitem open="0" type="814" id="7Dsh3RQhMBqr" />
|
||||||
|
<listitem open="0" type="814" id="o7d2CrsruJHZ" />
|
||||||
|
<listitem open="0" type="814" id="fRQUU8LUIdpp" />
|
||||||
|
<listitem open="0" type="814" id="tCGUEQs0VW0i" />
|
||||||
|
<listitem open="0" type="814" id="HHoVQbGDrTVa" />
|
||||||
|
<listitem open="0" type="815" id="IvRClCZ1LX9n" />
|
||||||
|
<listitem open="0" type="815" id="uUirWhfMjnAf" />
|
||||||
|
<listitem open="0" type="815" id="Ujr3jkVCgowi" />
|
||||||
|
<listitem open="0" type="815" id="Zvm4WIb2Z2yx" />
|
||||||
|
<listitem open="0" type="815" id="0U12xzu7s4bX" />
|
||||||
|
<listitem open="0" type="815" id="IjmpHLdfT2KV" />
|
||||||
|
<listitem open="0" type="815" id="5F2P6cAAbBHb" />
|
||||||
|
<listitem open="0" type="815" id="rfXl2OnJiltE" />
|
||||||
|
<listitem open="0" type="815" id="qZIqOH4DSRXm" />
|
||||||
|
<listitem open="0" type="815" id="tM3YAlRVdQgs" />
|
||||||
|
<listitem open="0" type="815" id="MKlnQwQyMUPk" />
|
||||||
|
</listitem>
|
||||||
|
<listitem open="0" type="830" id="Datatypes" >
|
||||||
|
<listitem open="1" type="829" id="blfxn9Uuu2yR" />
|
||||||
|
<listitem open="1" type="829" id="wqDoP5wfLOIc" />
|
||||||
|
<listitem open="1" type="829" id="U4XSIE3QJ6hx" />
|
||||||
|
<listitem open="1" type="829" id="63PN95L5vWtI" />
|
||||||
|
<listitem open="1" type="829" id="HMiS7gMcit21" />
|
||||||
|
<listitem open="1" type="829" id="IGSdGv66Dl0t" />
|
||||||
|
<listitem open="1" type="829" id="sDGZ4IaALxYS" />
|
||||||
|
<listitem open="1" type="829" id="bnxw9DWQZCtg" />
|
||||||
|
<listitem open="1" type="829" id="kedvoSFAnx4K" />
|
||||||
|
<listitem open="1" type="829" id="2rVxNPDwAAqK" />
|
||||||
|
<listitem open="1" type="829" id="8XzRUVsXMNSh" />
|
||||||
|
<listitem open="1" type="829" id="NNkuXbbOmpxp" />
|
||||||
|
</listitem>
|
||||||
|
<listitem open="1" type="831" id="ZqAwEabwEDr1" >
|
||||||
|
<listitem open="0" type="839" id="a2Smc4ipHYou" />
|
||||||
|
<listitem open="0" type="839" id="gnMEpp0PriC6" />
|
||||||
|
<listitem open="0" type="839" id="R3WGxP4bAOpz" />
|
||||||
|
</listitem>
|
||||||
|
<listitem open="1" type="831" id="ioL5YhpoYAWd" >
|
||||||
|
<listitem open="0" type="839" id="7C7bDTwbQv2H" />
|
||||||
|
<listitem open="0" type="839" id="DQHpEraw64eW" />
|
||||||
|
<listitem open="0" type="839" id="MsihEUMf7fjn" />
|
||||||
|
</listitem>
|
||||||
|
</listitem>
|
||||||
|
<listitem open="1" type="802" id="Use Case View" />
|
||||||
|
<listitem open="1" type="821" id="Component View" />
|
||||||
|
<listitem open="1" type="827" id="Deployment View" />
|
||||||
|
<listitem open="1" type="836" id="Entity Relationship Model" />
|
||||||
|
</listitem>
|
||||||
|
</listview>
|
||||||
|
<codegeneration>
|
||||||
|
<codegenerator language="C++" />
|
||||||
|
</codegeneration>
|
||||||
|
</XMI.extensions>
|
||||||
|
</XMI>
|
21
xpl/phpxpl/example.php
Normal file
21
xpl/phpxpl/example.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'xpllighting.class.php';
|
||||||
|
|
||||||
|
$xplinstance = new XPLLighting('192.168.0.50');
|
||||||
|
|
||||||
|
$running = true;
|
||||||
|
declare(ticks = 1) {
|
||||||
|
pcntl_signal( SIGINT, 'signalHandler' );
|
||||||
|
while($running) {
|
||||||
|
if ($xplinstance->doEvents()) {
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$xplinstance->detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
function signalHandler() {
|
||||||
|
global $running;
|
||||||
|
$running = false;
|
||||||
|
}
|
66
xpl/phpxpl/xpldevice.class.php
Normal file
66
xpl/phpxpl/xpldevice.class.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
define('DEFAULT_HBEAT_INTERVAL', 5);
|
||||||
|
|
||||||
|
class xPLDevice {
|
||||||
|
|
||||||
|
private $_heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||||
|
private $_port = 0;
|
||||||
|
private $_vendor = '';
|
||||||
|
private $_device = '';
|
||||||
|
private $_instance = '';
|
||||||
|
private $_address = '';
|
||||||
|
private $_lastHeartBeat = 0;
|
||||||
|
|
||||||
|
public function __construct( $vendor, $device = null ) {
|
||||||
|
if (is_null($device)) {
|
||||||
|
$dash = strpos($vendor, '-');
|
||||||
|
$dot = strpos($vendor, '.');
|
||||||
|
$this->_vendor = substr($vendor, 0, $dash);
|
||||||
|
$this->_device = substr($vendor, $dash+1, $dot-$dash-1);
|
||||||
|
$this->_instance = substr($vendor, $dot+1);
|
||||||
|
} else {
|
||||||
|
$this->_vendor = $vendor;
|
||||||
|
$this->_device = $device;
|
||||||
|
|
||||||
|
//Generate an instance
|
||||||
|
$randomNumber = mt_rand(1, 9999); //Generate ranom number between 1-9999
|
||||||
|
$this->_instance = sprintf('default%s', $randomNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function address() {
|
||||||
|
return $this->_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function heartBeatInterval() {
|
||||||
|
return $this->_heartBeatInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deviceName() {
|
||||||
|
return sprintf('%s-%s.%s', $this->_vendor, $this->_device, $this->_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lastHeartBeat() {
|
||||||
|
return $this->_lastHeartBeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function port() {
|
||||||
|
return $this->_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAddress( $address ) {
|
||||||
|
$this->_address = $address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeartBeatInterval( $minutes ) {
|
||||||
|
$this->_heartBeatInterval = $minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPort( $p ) {
|
||||||
|
$this->_port = $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLastHeartBeat( $timestamp ) {
|
||||||
|
$this->_lastHeartBeat = $timestamp;
|
||||||
|
}
|
||||||
|
}
|
210
xpl/phpxpl/xplinstance.class.php
Normal file
210
xpl/phpxpl/xplinstance.class.php
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'xplmessage.class.php';
|
||||||
|
require_once 'xpldevice.class.php';
|
||||||
|
|
||||||
|
define( XPL_PORT, 3865 );
|
||||||
|
|
||||||
|
class XPLInstance {
|
||||||
|
protected $_thisDevice = null;
|
||||||
|
protected $_devices = array();
|
||||||
|
|
||||||
|
private $_socket;
|
||||||
|
private $_isAttached = false;
|
||||||
|
private $_ip;
|
||||||
|
|
||||||
|
public function __construct($vendor, $device, $ip) {
|
||||||
|
$this->_ip = $ip;
|
||||||
|
$this->_thisDevice = new XPLDevice($vendor, $device);
|
||||||
|
|
||||||
|
$this->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attatched() {
|
||||||
|
return $this->_isAttatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detach() {
|
||||||
|
$message = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$message->setMessageSchemeIdentifier( 'hbeat.end' );
|
||||||
|
$message->setTarget('*');
|
||||||
|
$message->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$this->sendMessage( $message );
|
||||||
|
socket_close($this->_socket);
|
||||||
|
$this->_socket = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doEvents() {
|
||||||
|
$string = socket_read( $this->_socket, 1500);
|
||||||
|
if ($string != '') {
|
||||||
|
$message = XPLMessage::createMessageFromString($string);
|
||||||
|
if ($message) {
|
||||||
|
$this->processMessage( $message );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->poll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendMessage( $message, $device = null ) {
|
||||||
|
//echo "Sending heartbeat\n";
|
||||||
|
$msg = (string)$message;
|
||||||
|
socket_sendto( $this->_socket, $msg, strlen($msg), 0, '255.255.255.255', XPL_PORT );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function attatchedToNetwork() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleMessage( $message ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function bindToPort() {
|
||||||
|
$port = 49152;
|
||||||
|
//$port = XPL_PORT;
|
||||||
|
$error = 98;
|
||||||
|
while ($error == 98 && $port < 65535) {
|
||||||
|
if (@socket_bind($this->_socket, $this->_ip, $port) === false) {
|
||||||
|
++$port;
|
||||||
|
} else {
|
||||||
|
echo "Bind succeded as client on: " . $port . "\n";
|
||||||
|
return $port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function init() {
|
||||||
|
if (($this->_socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) === false) {
|
||||||
|
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_set_option( $this->_socket, SOL_SOCKET, SO_BROADCAST, 1);
|
||||||
|
socket_set_nonblock( $this->_socket );
|
||||||
|
|
||||||
|
$this->_thisDevice->setPort( $this->bindToPort() );
|
||||||
|
if ($this->_thisDevice->port() == 0) {
|
||||||
|
echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($this->_socket)) . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("xPL server started (bound to port %s)\n", $this->_thisDevice->port());
|
||||||
|
$this->sendHeartbeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function poll() {
|
||||||
|
if (!$this->attatched()) {
|
||||||
|
$this->sendHeartbeat();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time()-$this->_thisDevice->lastHeartBeat() >= $this->_thisDevice->heartBeatInterval() * 60) {
|
||||||
|
$this->sendHeartbeat();
|
||||||
|
}
|
||||||
|
//Loop all devices to see if they have timed out
|
||||||
|
foreach( $this->_devices as $key => $device ) {
|
||||||
|
if ( time()-$device->lastHeartBeat() >= $device->heartBeatInterval() * 60 * 2) {
|
||||||
|
printf("Device removed (timeout): %s\n", $device->deviceName());
|
||||||
|
|
||||||
|
//This is not a prefeered way of removing the item from an array
|
||||||
|
//Since we are iterating the loop will miss to check the new item.
|
||||||
|
//Here, it will be checked next time poll is called
|
||||||
|
unset($this->_devices[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processHeartBeat( $message ) {
|
||||||
|
if ($message->messageSchemeIdentifier() == 'hbeat.request') {
|
||||||
|
$this->sendHeartbeat();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach( $this->_devices as $key => $device ) {
|
||||||
|
if ( $device->deviceName() == $message->source() ) {
|
||||||
|
if (substr($message->messageSchemeIdentifier(), -3) == 'end') {
|
||||||
|
echo "Device removed: " . $message->source() . "\n";
|
||||||
|
unset($this->_devices[$key]);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$device->setLastHeartBeat( time() );
|
||||||
|
$device->setHeartBeatInterval( $message->bodyItem( 'interval' ) );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( (substr($message->messageSchemeIdentifier(), -3) != 'app') && (substr($message->messageSchemeIdentifier(), -5) != 'basic') ) { //Not a heartbeat
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf( "New device: %s\n", $message->source() );
|
||||||
|
$device = new xPLDevice( $message->source() );
|
||||||
|
$device->setHeartBeatInterval( $message->bodyItem('interval') );
|
||||||
|
$device->setLastHeartBeat( time() );
|
||||||
|
if ($message->messageSchemeIdentifier() == 'hbeat.app') {
|
||||||
|
$device->setAddress( $message->bodyItem('remote-ip'));
|
||||||
|
$device->setPort( $message->bodyItem('port') );
|
||||||
|
}
|
||||||
|
$this->_devices[] = $device;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processMessage( $message ) {
|
||||||
|
if (!$this->attatched() && $message->messageSchemeIdentifier() == 'hbeat.app' && $message->source() == $this->_thisDevice->deviceName()) {
|
||||||
|
//Our own echo
|
||||||
|
$this->setAttatched( true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($message->source() == $this->_thisDevice->deviceName()) {
|
||||||
|
//Ignore messages from ourselves
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( (substr($message->messageSchemeIdentifier(), 0, 5) == 'hbeat') || (substr($message->messageSchemeIdentifier(), 0, 6) == 'config') ) {
|
||||||
|
if ($this->processHeartBeat( $message )) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($message->target() != $this->_thisDevice->deviceName() && $message->target() != '*') {
|
||||||
|
//Message not for us
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!$this->handleMessage($message)) {
|
||||||
|
printf("Got message:\n%s", $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function sendHeartbeat() {
|
||||||
|
// echo "Sending heartbeat\n";
|
||||||
|
$message = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$message->setMessageSchemeIdentifier( 'hbeat.app' );
|
||||||
|
$message->setTarget('*');
|
||||||
|
$message->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$message->addBodyItem( 'interval', $this->_thisDevice->heartBeatInterval() );
|
||||||
|
$message->addBodyItem( 'port', $this->_thisDevice->port() );
|
||||||
|
$message->addBodyItem( 'remote-ip', $this->_ip );
|
||||||
|
$this->sendMessage( $message );
|
||||||
|
$this->_thisDevice->setLastHeartBeat( time() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setAttatched( $attatched ) {
|
||||||
|
$this->_isAttatched = $attatched;
|
||||||
|
if ($this->_isAttatched) {
|
||||||
|
echo "Attatched to xPL-network\n";
|
||||||
|
// timer->setInterval( 60000 ); //Once a minute
|
||||||
|
|
||||||
|
$message = new xPLMessage( xPLMessage::xplcmnd );
|
||||||
|
$message->setTarget( "*" );
|
||||||
|
$message->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$message->setMessageSchemeIdentifier( 'hbeat.request' );
|
||||||
|
$message->addBodyItem('command', 'request');
|
||||||
|
$this->sendMessage( $message );
|
||||||
|
|
||||||
|
$this->attatchedToNetwork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
172
xpl/phpxpl/xpllighting.class.php
Normal file
172
xpl/phpxpl/xpllighting.class.php
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'xplinstance.class.php';
|
||||||
|
|
||||||
|
class xPLLighting extends XPLInstance {
|
||||||
|
|
||||||
|
public function __construct($ip) {
|
||||||
|
parent::__construct('telldus', 'core', $ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function attatchedToNetwork() {
|
||||||
|
$message = new xPLMessage( xPLMessage::xpltrig );
|
||||||
|
$message->setMessageSchemeIdentifier( 'lighting.gateway' );
|
||||||
|
$message->setTarget('*');
|
||||||
|
$message->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$message->addBodyItem( 'report', 'gateway-ready' );
|
||||||
|
$this->sendMessage( $message );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleMessage( $message ) {
|
||||||
|
if ($message->messageSchemeIdentifier() == 'lighting.request') {
|
||||||
|
return $this->lightingRequest($message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function lightingRequest( $message ) {
|
||||||
|
switch( $message->bodyItem('request') ) {
|
||||||
|
case 'gateinfo':
|
||||||
|
return $this->gateInfo( );
|
||||||
|
case 'netlist':
|
||||||
|
return $this->netList( );
|
||||||
|
case 'netinfo':
|
||||||
|
return $this->netInfo( $message );
|
||||||
|
case 'devlist':
|
||||||
|
return $this->devList( $message );
|
||||||
|
case 'devinfo':
|
||||||
|
return $this->devInfo( $message );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function gateInfo( ) {
|
||||||
|
$message = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$message->setMessageSchemeIdentifier( 'lighting.gateinfo' );
|
||||||
|
$message->setTarget('*');
|
||||||
|
$message->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$message->addBodyItem( 'status', 'ok' );
|
||||||
|
$message->addBodyItem( 'protocol', 'TELLDUS' );
|
||||||
|
$message->addBodyItem( 'description', 'xPL to Telldus TellStick gateway' );
|
||||||
|
$message->addBodyItem( 'version', '1.0' );
|
||||||
|
$message->addBodyItem( 'author', 'Telldus Technologies AB' );
|
||||||
|
$message->addBodyItem( 'info-url', 'http://www.telldus.se' );
|
||||||
|
$message->addBodyItem( 'net-count', '1' );
|
||||||
|
$message->addBodyItem( 'preferred-net', '1' );
|
||||||
|
$message->addBodyItem( 'scenes-ok', 'false' );
|
||||||
|
$message->addBodyItem( 'channels-ok', 'false' );
|
||||||
|
$message->addBodyItem( 'fade-rate-ok', 'false' );
|
||||||
|
$this->sendMessage( $message );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function netList( ) {
|
||||||
|
$message = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$message->setMessageSchemeIdentifier( 'lighting.netlist' );
|
||||||
|
$message->setTarget('*');
|
||||||
|
$message->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$message->addBodyItem( 'status', 'ok' );
|
||||||
|
$message->addBodyItem( 'network', '1' );
|
||||||
|
$this->sendMessage( $message );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function netInfo( $message ) {
|
||||||
|
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$msg->setMessageSchemeIdentifier( 'lighting.netinfo' );
|
||||||
|
$msg->setTarget('*');
|
||||||
|
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
// print_r($message);
|
||||||
|
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||||
|
if ($msg->bodyItem('network') == '1') {
|
||||||
|
$msg->addBodyItem( 'status', 'ok' );
|
||||||
|
$msg->addBodyItem( 'name', exec('hostname') );
|
||||||
|
$msg->addBodyItem( 'device-count', tdGetNumberOfDevices() );
|
||||||
|
$msg->addBodyItem( 'scene-count', 0 );
|
||||||
|
} else {
|
||||||
|
$msg->addBodyItem( 'status', 'not-found' );
|
||||||
|
}
|
||||||
|
$this->sendMessage( $msg );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function devList( $message ) {
|
||||||
|
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$msg->setMessageSchemeIdentifier( 'lighting.devlist' );
|
||||||
|
$msg->setTarget('*');
|
||||||
|
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||||
|
if ($msg->bodyItem('network') == '1') {
|
||||||
|
$msg->addBodyItem( 'status', 'ok' );
|
||||||
|
$count = tdGetNumberOfDevices();
|
||||||
|
$deviceList = array();
|
||||||
|
for( $i = 0; $i < $count; ++$i ) {
|
||||||
|
$deviceList[] = tdGetDeviceId($i);
|
||||||
|
}
|
||||||
|
$msg->addBodyItem( 'device-count', $count );
|
||||||
|
$msg->addBodyItem( 'device', implode(',', $deviceList) );
|
||||||
|
} else {
|
||||||
|
$msg->addBodyItem( 'status', 'not-found' );
|
||||||
|
}
|
||||||
|
$this->sendMessage( $msg );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function devInfo( $message ) {
|
||||||
|
$found = false;
|
||||||
|
$count = tdGetNumberOfDevices();
|
||||||
|
$deviceId = $message->bodyItem('device');
|
||||||
|
for( $i = 0; $i < $count; ++$i ) {
|
||||||
|
if (tdGetDeviceId($i) == $deviceId) {
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$msg->setMessageSchemeIdentifier( 'lighting.devinfo' );
|
||||||
|
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||||
|
$msg->addBodyItem( 'device', $deviceId );
|
||||||
|
$msg->setTarget('*');
|
||||||
|
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
|
||||||
|
if ($msg->bodyItem('network') == '1' && $found) {
|
||||||
|
$methods = tdMethods($deviceId, TELLDUS_TURNON | TELLDUS_TURNOFF | TELLDUS_DIM );
|
||||||
|
$msg->addBodyItem( 'status', 'ok' );
|
||||||
|
$msg->addBodyItem( 'name', tdGetName($deviceId) );
|
||||||
|
$msg->addBodyItem( 'report-on-manual', 'false' );
|
||||||
|
$msg->addBodyItem( 'channel-count', '1');
|
||||||
|
$msg->addBodyItem( 'primary-channel', '1');
|
||||||
|
$msg->addBodyItem( 'channel', sprintf('1,%s,0,0', ($methods & TELLDUS_DIM ? 'true' : 'false')) );
|
||||||
|
$msg->addBodyItem( 'scene-count', '0');
|
||||||
|
} else {
|
||||||
|
$msg->addBodyItem( 'status', 'not-found' );
|
||||||
|
}
|
||||||
|
$this->sendMessage( $msg );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function scnList( $message ) {
|
||||||
|
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$msg->setMessageSchemeIdentifier( 'lighting.scnlist' );
|
||||||
|
$msg->setTarget('*');
|
||||||
|
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||||
|
$msg->addBodyItem( 'status', 'not-found' );
|
||||||
|
$this->sendMessage( $msg );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function scnInfo( $message ) {
|
||||||
|
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||||
|
$msg->setMessageSchemeIdentifier( 'lighting.scninfo' );
|
||||||
|
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||||
|
$msg->addBodyItem( 'scene', $message->bodyItem('scene') );
|
||||||
|
$msg->setTarget('*');
|
||||||
|
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||||
|
$msg->addBodyItem( 'status', 'not-found' );
|
||||||
|
$this->sendMessage( $msg );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
144
xpl/phpxpl/xplmessage.class.php
Normal file
144
xpl/phpxpl/xplmessage.class.php
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class xPLMessage {
|
||||||
|
|
||||||
|
private $_hop = 1;
|
||||||
|
private $_identifier = null;
|
||||||
|
private $_body = array();
|
||||||
|
private $_msi = '';
|
||||||
|
private $_source = '';
|
||||||
|
private $_target = '';
|
||||||
|
|
||||||
|
const xplcmnd = 1;
|
||||||
|
const xplstat = 2;
|
||||||
|
const xpltrig = 3;
|
||||||
|
|
||||||
|
public function __construct($identifier) {
|
||||||
|
$this->_identifier = $identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addBodyItem( $key, $value ) {
|
||||||
|
$this->_body[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addHeadItem( $key, $value ) {
|
||||||
|
if ($key == 'hop') {
|
||||||
|
$hop = (int)$value;
|
||||||
|
} else if ($key == 'source') {
|
||||||
|
$this->setSource($value);
|
||||||
|
} else if ($key == 'target') {
|
||||||
|
$this->setTarget($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bodyItem( $key ) {
|
||||||
|
if (array_key_exists($key, $this->_body)) {
|
||||||
|
return $this->_body[$key];
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messageSchemeIdentifier() {
|
||||||
|
return $this->_msi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function source() {
|
||||||
|
return $this->_source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function target() {
|
||||||
|
return $this->_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMessageSchemeIdentifier( $messageSchemeIdentifier ) {
|
||||||
|
$this->_msi = $messageSchemeIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSource( $value ) {
|
||||||
|
$this->_source = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTarget( $value ) {
|
||||||
|
$this->_target = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __tostring() {
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
switch( $this->_identifier ) {
|
||||||
|
case self::xplcmnd:
|
||||||
|
$message .= "xpl-cmnd\n";
|
||||||
|
break;
|
||||||
|
case self::xplstat:
|
||||||
|
$message .= "xpl-stat\n";
|
||||||
|
break;
|
||||||
|
case self::xpltrig:
|
||||||
|
$message .= "xpl-trig\n";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$message .= "{\n";
|
||||||
|
$message .= sprintf("hop=%s\n", $this->_hop);
|
||||||
|
$message .= sprintf("source=%s\n", $this->_source);
|
||||||
|
$message .= sprintf("target=%s\n", $this->_target);
|
||||||
|
$message .= "}\n";
|
||||||
|
$message .= $this->_msi . "\n";
|
||||||
|
$message .= "{\n";
|
||||||
|
foreach( $this->_body as $key => $value ) {
|
||||||
|
$message .= sprintf("%s=%s\n", $key, $value);
|
||||||
|
}
|
||||||
|
$message .= "}\n";
|
||||||
|
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createMessageFromString( $message ) {
|
||||||
|
$lines = explode("\n", $message);
|
||||||
|
$row = 0;
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
if ($lines[$row] == 'xpl-cmnd') {
|
||||||
|
$i = self::xplcmnd;
|
||||||
|
} else if ($lines[$row] == 'xpl-stat') {
|
||||||
|
$i = self::xplstat;
|
||||||
|
} else if ($lines[$row] == 'xpl-trig') {
|
||||||
|
$i = self::xpltrig;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++$row;
|
||||||
|
|
||||||
|
if ($lines[$row] != '{') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++$row;
|
||||||
|
|
||||||
|
$msg = new xPLMessage($i);
|
||||||
|
for(; $row < count($lines) && $lines[$row] != '}'; ++$row) {
|
||||||
|
list($name, $value) = explode( '=', $lines[$row] );
|
||||||
|
$msg->addHeadItem( $name, $value );
|
||||||
|
}
|
||||||
|
if ($row >= count($lines)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++$row;
|
||||||
|
|
||||||
|
$msg->setMessageSchemeIdentifier( $lines[$row] );
|
||||||
|
++$row;
|
||||||
|
|
||||||
|
if ($lines[$row] != '{') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++$row;
|
||||||
|
|
||||||
|
for(; $row < count($lines) && $lines[$row] != '}'; ++$row) {
|
||||||
|
list($name, $value) = explode( '=', $lines[$row] );
|
||||||
|
$msg->addBodyItem( $name, $value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
}
|
1
xpl/pyxpl/__init__.py
Normal file
1
xpl/pyxpl/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
__all__ = ["xplmessage", "xpldevice", "xplinstance"]
|
22
xpl/pyxpl/xpldevice.py
Normal file
22
xpl/pyxpl/xpldevice.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
###########################################################################
|
||||||
|
# Copyright (C) 2009 by Magnus Ahlberg
|
||||||
|
# <magnus.ahlberg@svart-katt.se>
|
||||||
|
#
|
||||||
|
# Copyright: See COPYING file that comes with this distribution
|
||||||
|
#
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
class XPLDevice:
|
||||||
|
"""A class to manage and xPL device"""
|
||||||
|
vendor = ""
|
||||||
|
device = ""
|
||||||
|
instance = ""
|
||||||
|
|
||||||
|
def __init__(devicename):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(vendor, device):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(vendor, device, instance):
|
||||||
|
pass
|
47
xpl/pyxpl/xplinstance.py
Normal file
47
xpl/pyxpl/xplinstance.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
###########################################################################
|
||||||
|
# Copyright (C) 2009 by Magnus Ahlberg
|
||||||
|
# <magnus.ahlberg@svart-katt.se>
|
||||||
|
#
|
||||||
|
# Copyright: See COPYING file that comes with this distribution
|
||||||
|
#
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
from xpldevice import *
|
||||||
|
|
||||||
|
from socket import *
|
||||||
|
|
||||||
|
class XPLInstance:
|
||||||
|
"""Class to handle an xPL session"""
|
||||||
|
MODE_UNDEFINED, MODE_CLIENT, MODE_DISCONNECTED, MODE_HUB = range(4)
|
||||||
|
|
||||||
|
__thisDevice = XPLDevice()
|
||||||
|
__devices = ()
|
||||||
|
__mode = MODE_UNDEFINED
|
||||||
|
|
||||||
|
def __init__(self, device):
|
||||||
|
self.__thisDevice = device
|
||||||
|
|
||||||
|
def __init__(self, vendor, deviceName):
|
||||||
|
device = XPLDevice(vendor, deviceName)
|
||||||
|
self.__init__(device)
|
||||||
|
|
||||||
|
def attached(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def devices(self):
|
||||||
|
return devices
|
||||||
|
|
||||||
|
def operationMode(self):
|
||||||
|
return operationMode
|
||||||
|
|
||||||
|
def sendMessage(self, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def sendMessage(self, message, device):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def bindToPort(self):
|
||||||
|
pass
|
56
xpl/pyxpl/xplmessage.py
Normal file
56
xpl/pyxpl/xplmessage.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
###########################################################################
|
||||||
|
# Copyright (C) 2009 by Magnus Ahlberg
|
||||||
|
# <magnus.ahlberg@svart-katt.se>
|
||||||
|
#
|
||||||
|
# Copyright: See COPYING file that comes with this distribution
|
||||||
|
#
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
class XPLMessage:
|
||||||
|
"""A class for managing xPL messages"""
|
||||||
|
ID_UNDEFINED, ID_XPLCMND, ID_XPLSTAT, ID_XPLTRIG = range(4)
|
||||||
|
__body = {}
|
||||||
|
__hop = 0
|
||||||
|
__source = ""
|
||||||
|
__target = ""
|
||||||
|
__identifier = ID_UNDEFINED
|
||||||
|
__identifierString = ("-", "xpl-cmnd", "xpl-stat", "xpl-trig")
|
||||||
|
__messageSchemaIdentifier = ""
|
||||||
|
|
||||||
|
def __init__(self, identifier, messageSchemaIdentifier):
|
||||||
|
self.__identifier = identifier
|
||||||
|
self.__messageSchemaIdentifier = messageSchemaIdentifier
|
||||||
|
|
||||||
|
def addBodyItem(self, key, value):
|
||||||
|
self.__body[key] = value
|
||||||
|
|
||||||
|
def bodyItem(self, key):
|
||||||
|
return self.__body[key]
|
||||||
|
|
||||||
|
def createMessageFromString(message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def setSource(self, value):
|
||||||
|
self.__source = value
|
||||||
|
|
||||||
|
def setTarget(self, value):
|
||||||
|
self.__target = value
|
||||||
|
|
||||||
|
def toString(self):
|
||||||
|
if self.__identifier == self.ID_UNDEFINED:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
messageStringList = []
|
||||||
|
messageStringList.append(self.__identifierString[self.__identifier] + "\n")
|
||||||
|
messageStringList.append("{\n")
|
||||||
|
messageStringList.append("hop=" + str(self.__hop) + "\n")
|
||||||
|
messageStringList.append("source=" + self.__source + "\n")
|
||||||
|
messageStringList.append("target=" + self.__target + "\n")
|
||||||
|
messageStringList.append("}\n")
|
||||||
|
messageStringList.append(self.__messageSchemaIdentifier + "\n")
|
||||||
|
messageStringList.append("{\n")
|
||||||
|
for key, value in self.__body.iteritems():
|
||||||
|
messageStringList.append(key + "=" + value + "\n")
|
||||||
|
messageStringList.append("}\n")
|
||||||
|
|
||||||
|
return "".join(messageStringList)
|
43
xpl/qtxpl/CMakeLists.txt
Normal file
43
xpl/qtxpl/CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||||
|
PROJECT(qtxpl)
|
||||||
|
|
||||||
|
FIND_PACKAGE( Qt4 REQUIRED )
|
||||||
|
SET(QT_USE_QTNETWORK TRUE)
|
||||||
|
INCLUDE( ${QT_USE_FILE} )
|
||||||
|
|
||||||
|
SET( QTXPL_SRCS
|
||||||
|
xpldevice.cpp
|
||||||
|
xplinstance.cpp
|
||||||
|
xplmessage.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
SET( QTXPL_HDRS
|
||||||
|
xpldevice.h
|
||||||
|
)
|
||||||
|
|
||||||
|
SET( QTXPL_MOC_HDRS
|
||||||
|
xplinstance.h
|
||||||
|
xplmessage.h
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
QT4_WRAP_CPP( QTXPL_MOC_SRCS ${QTXPL_MOC_HDRS} )
|
||||||
|
QT4_AUTOMOC ( ${QTXPL_SRCS} )
|
||||||
|
|
||||||
|
|
||||||
|
SET( QTXPL_LIBRARIES
|
||||||
|
${QT_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_DEFINITIONS(${QT_DEFINITIONS})
|
||||||
|
ADD_DEFINITIONS(-DQT_NO_DEBUG)
|
||||||
|
|
||||||
|
ADD_LIBRARY("qtxpl" SHARED
|
||||||
|
${QTXPL_SRCS}
|
||||||
|
${QTXPL_HDRS}
|
||||||
|
${QTXPL_MOC_HDRS}
|
||||||
|
${QTXPL_MOC_SRCS}
|
||||||
|
)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES( "qtxpl" ${QTXPL_LIBRARIES} )
|
||||||
|
|
12
xpl/qtxpl/main.cpp
Normal file
12
xpl/qtxpl/main.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
|
#include "xplinstance.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QCoreApplication a(argc, argv);
|
||||||
|
|
||||||
|
/*xPLInstance *instance = */new xPLInstance("telldus", "center");
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
15
xpl/qtxpl/qtxpl.pro
Normal file
15
xpl/qtxpl/qtxpl.pro
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# -------------------------------------------------
|
||||||
|
# Project created by QtCreator 2009-03-05T16:12:24
|
||||||
|
# -------------------------------------------------
|
||||||
|
QT += network
|
||||||
|
QT -= gui
|
||||||
|
TARGET = qtxpl
|
||||||
|
CONFIG += console
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
TEMPLATE = lib
|
||||||
|
SOURCES += xpldevice.cpp \
|
||||||
|
xplinstance.cpp \
|
||||||
|
xplmessage.cpp
|
||||||
|
HEADERS += xpldevice.h \
|
||||||
|
xplinstance.h \
|
||||||
|
xplmessage.h
|
105
xpl/qtxpl/xpldevice.cpp
Normal file
105
xpl/qtxpl/xpldevice.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#include "xpldevice.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
const int DEFAULT_HBEAT_INTERVAL = 5;
|
||||||
|
|
||||||
|
class xPLDevicePrivate {
|
||||||
|
public:
|
||||||
|
QString vendor, device, instance;
|
||||||
|
QDateTime lastHeartBeat;
|
||||||
|
int port, heartBeatInterval;
|
||||||
|
QHostAddress address;
|
||||||
|
};
|
||||||
|
|
||||||
|
xPLDevice::xPLDevice( const xPLDevice &other )
|
||||||
|
: d( new xPLDevicePrivate( *other.d ))
|
||||||
|
{
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLDevice& xPLDevice::operator=( xPLDevice other ) {
|
||||||
|
std::swap( this->d, other.d );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLDevice::xPLDevice( const QString &deviceName )
|
||||||
|
:d(new xPLDevicePrivate)
|
||||||
|
{
|
||||||
|
d->port = 0;
|
||||||
|
d->heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||||
|
QString name = deviceName.section('.', 0, 0);
|
||||||
|
d->vendor = name.section('-', 0, 0);
|
||||||
|
d->device = name.section('-', 1, 1);
|
||||||
|
d->instance = deviceName.section('.', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLDevice::xPLDevice( const QString &vendor, const QString &device )
|
||||||
|
:d(new xPLDevicePrivate)
|
||||||
|
{
|
||||||
|
d->vendor = vendor;
|
||||||
|
d->device = device;
|
||||||
|
d->instance = "";
|
||||||
|
d->port = 0;
|
||||||
|
d->heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||||
|
|
||||||
|
//Seed the random number generator
|
||||||
|
srand( (unsigned int)time( NULL ) );
|
||||||
|
|
||||||
|
//Generate an instance
|
||||||
|
int randomNumber = rand() % 9999 + 1; //Generate ranom number between 1-9999
|
||||||
|
d->instance = QString("default%1").arg(randomNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLDevice::xPLDevice( const QString &vendor, const QString &device, const QString &instance )
|
||||||
|
:d(new xPLDevicePrivate)
|
||||||
|
{
|
||||||
|
d->vendor = vendor;
|
||||||
|
d->device = device;
|
||||||
|
d->instance = instance;
|
||||||
|
d->port = 0;
|
||||||
|
d->heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLDevice::~xPLDevice() {
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHostAddress xPLDevice::address() const {
|
||||||
|
return d->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xPLDevice::heartBeatInterval() const {
|
||||||
|
return d->heartBeatInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString xPLDevice::deviceName() const {
|
||||||
|
return QString("%1-%2.%3").arg(d->vendor).arg(d->device).arg(d->instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime xPLDevice::lastHeartBeat() const {
|
||||||
|
return d->lastHeartBeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xPLDevice::port() const {
|
||||||
|
return d->port;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLDevice::setAddress( const QHostAddress &address ) {
|
||||||
|
d->address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLDevice::setHeartBeatInterval( int minutes ) {
|
||||||
|
d->heartBeatInterval = minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLDevice::setPort( int p ) {
|
||||||
|
d->port = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLDevice::setLastHeartBeat( const QDateTime ×tamp ) {
|
||||||
|
d->lastHeartBeat = timestamp;
|
||||||
|
}
|
38
xpl/qtxpl/xpldevice.h
Normal file
38
xpl/qtxpl/xpldevice.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef XPLDEVICE_H
|
||||||
|
#define XPLDEVICE_H
|
||||||
|
|
||||||
|
#include "xplmessage.h"
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QHostAddress>
|
||||||
|
|
||||||
|
class xPLDevicePrivate;
|
||||||
|
|
||||||
|
class QTXPL_EXPORT xPLDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
xPLDevice( const xPLDevice & ); //Copy constructor
|
||||||
|
xPLDevice& operator=( xPLDevice ); //Copy assignment operator
|
||||||
|
|
||||||
|
xPLDevice( const QString &deviceName );
|
||||||
|
xPLDevice( const QString &vendor, const QString &device );
|
||||||
|
xPLDevice( const QString &vendor, const QString &device, const QString &instance );
|
||||||
|
|
||||||
|
~xPLDevice();
|
||||||
|
|
||||||
|
QString deviceName() const;
|
||||||
|
|
||||||
|
QDateTime lastHeartBeat() const;
|
||||||
|
|
||||||
|
QHostAddress address() const;
|
||||||
|
int heartBeatInterval() const;
|
||||||
|
int port() const;
|
||||||
|
void setAddress( const QHostAddress &address );
|
||||||
|
void setHeartBeatInterval( int minutes );
|
||||||
|
void setPort( int port );
|
||||||
|
void setLastHeartBeat( const QDateTime ×tamp );
|
||||||
|
|
||||||
|
private:
|
||||||
|
xPLDevicePrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // XPLDEVICE_H
|
226
xpl/qtxpl/xplinstance.cpp
Normal file
226
xpl/qtxpl/xplinstance.cpp
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
#include "xplinstance.h"
|
||||||
|
#include "xplmessage.h"
|
||||||
|
|
||||||
|
#include <QUdpSocket>
|
||||||
|
#include <QLinkedList>
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
class xPLInstancePrivate {
|
||||||
|
public:
|
||||||
|
xPLDevice *thisDevice;
|
||||||
|
QLinkedList<xPLDevice> devices;
|
||||||
|
QUdpSocket *socket;
|
||||||
|
xPLInstance::OperationMode mode;
|
||||||
|
QHostAddress address;
|
||||||
|
bool isAttatched;
|
||||||
|
QTimer *timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
xPLInstance::xPLInstance( const xPLDevice &device, QObject *parent )
|
||||||
|
:QObject(parent)
|
||||||
|
{
|
||||||
|
d = new xPLInstancePrivate;
|
||||||
|
d->thisDevice = new xPLDevice(device);
|
||||||
|
d->mode = Disconnected;
|
||||||
|
d->timer = new QTimer(this);
|
||||||
|
this->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLInstance::xPLInstance( const QString &vendor, const QString &device, QObject *parent )
|
||||||
|
:QObject(parent)
|
||||||
|
{
|
||||||
|
d = new xPLInstancePrivate;
|
||||||
|
d->thisDevice = new xPLDevice(vendor, device);
|
||||||
|
d->mode = Disconnected;
|
||||||
|
d->timer = new QTimer(this);
|
||||||
|
this->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLInstance::~xPLInstance() {
|
||||||
|
delete d->thisDevice;
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::init() {
|
||||||
|
foreach(QHostAddress address, QNetworkInterface::allAddresses()) {
|
||||||
|
if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress::LocalHost) {
|
||||||
|
d->address = address;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d->isAttatched = false;
|
||||||
|
d->socket = new QUdpSocket(this);
|
||||||
|
d->thisDevice->setPort(this->bindToPort());
|
||||||
|
if (d->thisDevice->port() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->timer->setInterval( 3000 );
|
||||||
|
connect(d->socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
|
||||||
|
connect(d->timer, SIGNAL(timeout()), this, SLOT(poll()));
|
||||||
|
this->sendHeartbeat();
|
||||||
|
d->timer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xPLInstance::attatched() const {
|
||||||
|
return this->d->isAttatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xPLInstance::bindToPort() {
|
||||||
|
//Hub-mode not supported
|
||||||
|
/*if (d->socket->bind( XPL_PORT )) {
|
||||||
|
d->mode = Hub;
|
||||||
|
qDebug("Bind succeded as hub");
|
||||||
|
return XPL_PORT;
|
||||||
|
}*/
|
||||||
|
for (int port = 49152; port <= 65535; ++port) {
|
||||||
|
if (d->socket->bind( port, QUdpSocket::DontShareAddress )) {
|
||||||
|
d->mode = Client;
|
||||||
|
qDebug() << "Bind succeded as client on" << port;
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug("Bind failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLInstance::OperationMode xPLInstance::operationMode() const {
|
||||||
|
return d->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::processPendingDatagrams() {
|
||||||
|
while (d->socket->hasPendingDatagrams()) {
|
||||||
|
QByteArray datagram;
|
||||||
|
datagram.resize(d->socket->pendingDatagramSize());
|
||||||
|
d->socket->readDatagram(datagram.data(), datagram.size());
|
||||||
|
xPLMessage *message = xPLMessage::createMessageFromString( datagram.data() );
|
||||||
|
if (message) {
|
||||||
|
processMessage( *message );
|
||||||
|
delete message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::poll() {
|
||||||
|
if (!attatched()) {
|
||||||
|
sendHeartbeat();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (d->thisDevice->lastHeartBeat().secsTo( QDateTime::currentDateTime() ) >= d->thisDevice->heartBeatInterval() * 60) {
|
||||||
|
sendHeartbeat();
|
||||||
|
}
|
||||||
|
//Loop all devices to see if they have timed out
|
||||||
|
for( QLinkedList<xPLDevice>::iterator it = d->devices.begin(); it != d->devices.end(); ) {
|
||||||
|
if ((*it).lastHeartBeat().secsTo( QDateTime::currentDateTime() ) >= (*it).heartBeatInterval() * 60 * 2) {
|
||||||
|
qDebug() << "Device removed (timeout):" << (*it).deviceName();
|
||||||
|
it = d->devices.erase( it );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::sendMessage( const xPLMessage &msg ) const {
|
||||||
|
xPLMessage message(msg); //Copy so we don't have const
|
||||||
|
message.setSource(d->thisDevice->deviceName());
|
||||||
|
QByteArray datagram = message.toString().toAscii();
|
||||||
|
d->socket->writeDatagram(datagram.data(), datagram.size(), QHostAddress::Broadcast, XPL_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::sendMessage( xPLMessage * message ) const {
|
||||||
|
this->sendMessage(*message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::sendMessage( const xPLMessage &message, const xPLDevice &device ) const {
|
||||||
|
QByteArray datagram = message.toString().toAscii();
|
||||||
|
d->socket->writeDatagram(datagram.data(), datagram.size(), device.address(), device.port());
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::processHeartBeat( const xPLMessage &message ) {
|
||||||
|
if (message.messageSchemeIdentifier() == "hbeat.request") {
|
||||||
|
sendHeartbeat();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for( QLinkedList<xPLDevice>::iterator it = d->devices.begin(); it != d->devices.end(); ++it ) {
|
||||||
|
if ( (*it).deviceName() == message.source() ) {
|
||||||
|
if (message.messageSchemeIdentifier() == "hbeat.end") {
|
||||||
|
qDebug() << "Device removed:" << message.source();
|
||||||
|
d->devices.erase( it );
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
(*it).setLastHeartBeat( QDateTime::currentDateTime() );
|
||||||
|
(*it).setHeartBeatInterval( message.bodyItem( "interval" ).toInt() );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!message.messageSchemeIdentifier().endsWith("app") && !message.messageSchemeIdentifier().endsWith("basic")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << "New device:" << message.source();
|
||||||
|
xPLDevice device( message.source() );
|
||||||
|
device.setHeartBeatInterval( message.bodyItem("interval").toInt() );
|
||||||
|
device.setLastHeartBeat( QDateTime::currentDateTime() );
|
||||||
|
if (message.messageSchemeIdentifier() == "hbeat.app") {
|
||||||
|
device.setAddress( QHostAddress(message.bodyItem("remote-ip")) );
|
||||||
|
device.setPort( message.bodyItem("port").toInt() );
|
||||||
|
}
|
||||||
|
d->devices.append( device );
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::processMessage( const xPLMessage &message ) {
|
||||||
|
if (!attatched() && message.messageSchemeIdentifier() == "hbeat.app" && message.source() == d->thisDevice->deviceName()) {
|
||||||
|
//Our own echo
|
||||||
|
setAttatched( true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message.source() == d->thisDevice->deviceName()) {
|
||||||
|
//Ignore messages from ourselves
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message.messageSchemeIdentifier().startsWith("hbeat") || message.messageSchemeIdentifier().startsWith("config")) {
|
||||||
|
processHeartBeat( message );
|
||||||
|
}
|
||||||
|
if (d->mode == xPLInstance::Hub) {
|
||||||
|
//Reply the message to all clients
|
||||||
|
for( QLinkedList<xPLDevice>::iterator it = d->devices.begin(); it != d->devices.end(); ++it ) {
|
||||||
|
sendMessage(message, *it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message.target() != d->thisDevice->deviceName() && message.target() != "*") {
|
||||||
|
//Message not for us
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xPLMessage newMsg(message);
|
||||||
|
emit messageReceived(&newMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::sendHeartbeat() {
|
||||||
|
xPLMessage message( xPLMessage::xplstat );
|
||||||
|
message.setMessageSchemeIdentifier( "hbeat.app" );
|
||||||
|
message.setTarget("*");
|
||||||
|
message.setSource( d->thisDevice->deviceName() );
|
||||||
|
message.addBodyItem( "interval", QString::number(d->thisDevice->heartBeatInterval()) );
|
||||||
|
message.addBodyItem( "port", QString::number(d->thisDevice->port()) );
|
||||||
|
message.addBodyItem( "remote-ip", d->address.toString() );
|
||||||
|
sendMessage( message );
|
||||||
|
d->thisDevice->setLastHeartBeat( QDateTime::currentDateTime() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLInstance::setAttatched( bool attatched ) {
|
||||||
|
d->isAttatched = attatched;
|
||||||
|
if (d->isAttatched) {
|
||||||
|
qDebug() << "Attached to network!";
|
||||||
|
d->timer->setInterval( 60000 ); //Once a minute
|
||||||
|
|
||||||
|
xPLMessage message( xPLMessage::xplcmnd );
|
||||||
|
message.setTarget( "*" );
|
||||||
|
message.setSource( d->thisDevice->deviceName() );
|
||||||
|
message.setMessageSchemeIdentifier( "hbeat.request" );
|
||||||
|
message.addBodyItem("command", "request");
|
||||||
|
sendMessage( message );
|
||||||
|
emit attachedToNetwork();
|
||||||
|
}
|
||||||
|
}
|
55
xpl/qtxpl/xplinstance.h
Normal file
55
xpl/qtxpl/xplinstance.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef XPLINSTANCE_H
|
||||||
|
#define XPLINSTANCE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "xpldevice.h"
|
||||||
|
#include "xplmessage.h"
|
||||||
|
|
||||||
|
const int XPL_PORT = 3865;
|
||||||
|
|
||||||
|
class QTimer;
|
||||||
|
class xPLInstancePrivate;
|
||||||
|
|
||||||
|
class QTXPL_EXPORT xPLInstance : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_ENUMS( OperationMode );
|
||||||
|
|
||||||
|
Q_PROPERTY( OperationMode operationMode READ operationMode );
|
||||||
|
public:
|
||||||
|
enum OperationMode { Client, Disconnected, Hub };
|
||||||
|
|
||||||
|
xPLInstance( const xPLDevice &device, QObject *parent = 0 );
|
||||||
|
xPLInstance( const QString &vendor, const QString &device, QObject *parent = 0 );
|
||||||
|
~xPLInstance();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool attatched() const;
|
||||||
|
|
||||||
|
OperationMode operationMode() const;
|
||||||
|
|
||||||
|
void sendMessage( const xPLMessage &message ) const;
|
||||||
|
void sendMessage( xPLMessage * message ) const;
|
||||||
|
void sendMessage( const xPLMessage &message, const xPLDevice &device ) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void messageReceived(xPLMessage *message);
|
||||||
|
void attachedToNetwork();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void processPendingDatagrams();
|
||||||
|
void sendHeartbeat();
|
||||||
|
void poll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void processHeartBeat( const xPLMessage &message );
|
||||||
|
void processMessage( const xPLMessage &message );
|
||||||
|
void init();
|
||||||
|
int bindToPort();
|
||||||
|
void setAttatched( bool attatched );
|
||||||
|
|
||||||
|
xPLInstancePrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // XPLINSTANCE_H
|
188
xpl/qtxpl/xplmessage.cpp
Normal file
188
xpl/qtxpl/xplmessage.cpp
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#include "xplmessage.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
class xPLMessage::xPLMessagePrivate {
|
||||||
|
public:
|
||||||
|
xPLMessage::Identifier identifier;
|
||||||
|
int hop;
|
||||||
|
QString source, target, msi;
|
||||||
|
QMap<QString, QString> headExtra, body;
|
||||||
|
};
|
||||||
|
|
||||||
|
xPLMessage::xPLMessage( const xPLMessage &other )
|
||||||
|
: QObject(),
|
||||||
|
d( new xPLMessagePrivate( *other.d ))
|
||||||
|
{
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLMessage& xPLMessage::operator=( xPLMessage other ) {
|
||||||
|
std::swap( this->d, other.d );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
xPLMessage::xPLMessage(Identifier i)
|
||||||
|
:QObject(),
|
||||||
|
d(new xPLMessagePrivate)
|
||||||
|
{
|
||||||
|
d->hop = 1;
|
||||||
|
d->identifier = i;
|
||||||
|
d->target = "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLMessage::xPLMessage()
|
||||||
|
:QObject(),
|
||||||
|
d(new xPLMessagePrivate)
|
||||||
|
{
|
||||||
|
|
||||||
|
d->hop = 1;
|
||||||
|
d->identifier = xplcmnd;
|
||||||
|
d->target = "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLMessage::~xPLMessage() {
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xPLMessage::addBodyItem( const QString &key, const QString &value ) {
|
||||||
|
d->body[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLMessage::addHeadItem( const QString &key, const QString &value ) {
|
||||||
|
if (key == "hop") {
|
||||||
|
d->hop = value.toInt();
|
||||||
|
} else if (key == "source") {
|
||||||
|
setSource(value);
|
||||||
|
} else if (key == "target") {
|
||||||
|
setTarget(value);
|
||||||
|
} else {
|
||||||
|
d->headExtra[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString xPLMessage::bodyItem( const QString &key ) const {
|
||||||
|
if (d->body.contains(key)) {
|
||||||
|
return d->body[key];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString xPLMessage::headItem( const QString &key ) const {
|
||||||
|
if (d->headExtra.contains(key)) {
|
||||||
|
return d->headExtra[key];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString xPLMessage::messageSchemeIdentifier() const {
|
||||||
|
return d->msi;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString xPLMessage::source() const {
|
||||||
|
return d->source;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString xPLMessage::target() const {
|
||||||
|
return d->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLMessage::setMessageSchemeIdentifier( const QString &messageSchemeIdentifier ) {
|
||||||
|
d->msi = messageSchemeIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLMessage::setSource( const QString &value ) {
|
||||||
|
d->source = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xPLMessage::setTarget( const QString &value ) {
|
||||||
|
d->target = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString xPLMessage::toString() const {
|
||||||
|
QString message;
|
||||||
|
|
||||||
|
switch( d->identifier ) {
|
||||||
|
case xplcmnd:
|
||||||
|
message += "xpl-cmnd\n";
|
||||||
|
break;
|
||||||
|
case xplstat:
|
||||||
|
message += "xpl-stat\n";
|
||||||
|
break;
|
||||||
|
case xpltrig:
|
||||||
|
message += "xpl-trig\n";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
message += "{\n";
|
||||||
|
message += QString("hop=%1\n").arg(d->hop);
|
||||||
|
message += QString("source=%1\n").arg(d->source);
|
||||||
|
message += QString("target=%1\n").arg(d->target);
|
||||||
|
for( QMap<QString, QString>::const_iterator it = d->headExtra.begin(); it != d->headExtra.end(); ++it ) {
|
||||||
|
message += QString("%1=%2\n").arg(it.key()).arg(it.value());
|
||||||
|
}
|
||||||
|
message += "}\n";
|
||||||
|
message += d->msi + "\n";
|
||||||
|
message += "{\n";
|
||||||
|
for( QMap<QString, QString>::const_iterator it = d->body.begin(); it != d->body.end(); ++it ) {
|
||||||
|
message += QString("%1=%2\n").arg(it.key()).arg(it.value());
|
||||||
|
}
|
||||||
|
message += "}\n";
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
xPLMessage *xPLMessage::createMessageFromString( const QString &message ) {
|
||||||
|
QStringList lines = message.split('\n', QString::SkipEmptyParts);
|
||||||
|
QStringList::const_iterator it = lines.begin();
|
||||||
|
|
||||||
|
Identifier i;
|
||||||
|
|
||||||
|
if (*it == "xpl-cmnd") {
|
||||||
|
i = xplcmnd;
|
||||||
|
} else if (*it == "xpl-stat") {
|
||||||
|
i = xplstat;
|
||||||
|
} else if (*it == "xpl-trig") {
|
||||||
|
i = xpltrig;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
|
||||||
|
if (*it != "{") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
|
||||||
|
xPLMessage *msg = new xPLMessage(i);
|
||||||
|
for(; it != lines.end() && *it != "}"; ++it) {
|
||||||
|
msg->addHeadItem( (*it).section('=', 0, 0), (*it).section('=', 1) );
|
||||||
|
}
|
||||||
|
if (it == lines.end()) {
|
||||||
|
delete msg;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
|
||||||
|
msg->setMessageSchemeIdentifier( *it );
|
||||||
|
++it;
|
||||||
|
|
||||||
|
if (*it != "{") {
|
||||||
|
delete msg;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
|
||||||
|
for(; it != lines.end() && *it != "}"; ++it) {
|
||||||
|
msg->addBodyItem( (*it).section('=', 0, 0), (*it).section('=', 1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
57
xpl/qtxpl/xplmessage.h
Normal file
57
xpl/qtxpl/xplmessage.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef XPLMESSAGE_H
|
||||||
|
#define XPLMESSAGE_H
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
#ifdef qtxpl_EXPORTS
|
||||||
|
#define QTXPL_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define QTXPL_EXPORT __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define QTXPL_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
class QTXPL_EXPORT xPLMessage : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_ENUMS( Identifier );
|
||||||
|
public:
|
||||||
|
enum Identifier { xplcmnd, xplstat, xpltrig };
|
||||||
|
|
||||||
|
xPLMessage( const xPLMessage & ); //Copy constructor
|
||||||
|
xPLMessage& operator=( xPLMessage ); //Copy assignment operator
|
||||||
|
|
||||||
|
xPLMessage(Identifier identifier);
|
||||||
|
xPLMessage();
|
||||||
|
virtual ~xPLMessage();
|
||||||
|
|
||||||
|
static xPLMessage *createMessageFromString( const QString &message );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void addBodyItem( const QString &key, const QString &value );
|
||||||
|
void addHeadItem( const QString &key, const QString &value );
|
||||||
|
|
||||||
|
QString bodyItem( const QString &key ) const;
|
||||||
|
QString headItem( const QString &key ) const;
|
||||||
|
QString messageSchemeIdentifier() const;
|
||||||
|
QString source() const;
|
||||||
|
QString target() const;
|
||||||
|
|
||||||
|
void setMessageSchemeIdentifier( const QString &msi );
|
||||||
|
void setSource( const QString &value );
|
||||||
|
void setTarget( const QString &value );
|
||||||
|
|
||||||
|
QString toString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class xPLMessagePrivate;
|
||||||
|
xPLMessagePrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(xPLMessage*)
|
||||||
|
|
||||||
|
#endif // XPLMESSAGE_H
|
37
xpl/telldus-core-xpl/Makefile
Normal file
37
xpl/telldus-core-xpl/Makefile
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#
|
||||||
|
# Makefile for xPLLib
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# For LINUX, use the following
|
||||||
|
CCOPTS = -g -DLINUX -pedantic -Wall
|
||||||
|
LIBS = -g -lm -lxPL -ltelldus-core
|
||||||
|
|
||||||
|
LDOPTS = -O
|
||||||
|
CC = cc $(CCOPTS)
|
||||||
|
LD = cc $(LDOPTS)
|
||||||
|
|
||||||
|
CMD_LIST = xPL_TelldusCore
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) -c $<
|
||||||
|
|
||||||
|
.o:
|
||||||
|
$(LD) -o $@ $< $(LIBS)
|
||||||
|
|
||||||
|
.c:
|
||||||
|
$(CC) -c $<
|
||||||
|
$(LD) -o $@ $< $(LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
all: ${CMD_LIST}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.a core ${CMD_LIST}
|
||||||
|
|
||||||
|
rebuild: clean all
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
399
xpl/telldus-core-xpl/xPL_TelldusCore.c
Normal file
399
xpl/telldus-core-xpl/xPL_TelldusCore.c
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <xPL.h>
|
||||||
|
#include <telldus-core.h>
|
||||||
|
|
||||||
|
#define TELLDUS_VERSION "1.0"
|
||||||
|
#define INSTANCE_MAX 16
|
||||||
|
|
||||||
|
static xPL_ServicePtr telldusService = NULL;
|
||||||
|
static Bool daemonMode = TRUE;
|
||||||
|
char hostname[INSTANCE_MAX];
|
||||||
|
|
||||||
|
void sendDevInfo(xPL_MessagePtr msg);
|
||||||
|
void sendDevList(xPL_MessagePtr msg);
|
||||||
|
void sendGatewayInfo();
|
||||||
|
void sendNetInfo(xPL_MessagePtr msg);
|
||||||
|
void sendNetList();
|
||||||
|
|
||||||
|
void lightingCommandHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue) {
|
||||||
|
Bool found = FALSE;
|
||||||
|
int deviceCount = 0, deviceId = 0, i, level = 0;
|
||||||
|
|
||||||
|
if (!xPL_doesMessageNamedValueExist(theMessage, "command")) {
|
||||||
|
return;
|
||||||
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "command"), "goto") != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xPL_doesMessageNamedValueExist(theMessage, "network")) {
|
||||||
|
return;
|
||||||
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "network"), "1") != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xPL_doesMessageNamedValueExist(theMessage, "device")) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* Loop the devices to see it realy exists */
|
||||||
|
deviceCount = tdGetNumberOfDevices();
|
||||||
|
|
||||||
|
xPL_strToInt(xPL_getMessageNamedValue(theMessage, "device"), &deviceId);
|
||||||
|
for( i = 0; i < deviceCount; ++i ) {
|
||||||
|
if (tdGetDeviceId(i) == deviceId) {
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found == FALSE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xPL_doesMessageNamedValueExist(theMessage, "level")) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
xPL_strToInt(xPL_getMessageNamedValue(theMessage, "level"), &level);
|
||||||
|
if (level < 0 || level > 100) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
level = (float)level * 255.0 / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level > 0 && level < 255) {
|
||||||
|
/* See if the device supports dim */
|
||||||
|
if (!(tdMethods(deviceId, TELLSTICK_DIM) & TELLSTICK_DIM)) {
|
||||||
|
/* Non dimmable device was dimmed */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tdDim(deviceId, (unsigned char)level);
|
||||||
|
} else if (level == 255) {
|
||||||
|
/* See if the device supports dim */
|
||||||
|
if (!(tdMethods(deviceId, TELLSTICK_TURNON) & TELLSTICK_TURNON)) {
|
||||||
|
/* Non dimmable device was dimmed */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tdTurnOn(deviceId);
|
||||||
|
} else if (level == 0) {
|
||||||
|
/* See if the device supports dim */
|
||||||
|
if (!(tdMethods(deviceId, TELLSTICK_TURNOFF) & TELLSTICK_TURNOFF)) {
|
||||||
|
/* Non dimmable device was dimmed */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tdTurnOff(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void lightingRequestHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue) {
|
||||||
|
|
||||||
|
if (!xPL_doesMessageNamedValueExist(theMessage, "request")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "devinfo") == 0) {
|
||||||
|
sendDevInfo(theMessage);
|
||||||
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "devlist") == 0) {
|
||||||
|
sendDevList(theMessage);
|
||||||
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "gateinfo") == 0) {
|
||||||
|
sendGatewayInfo();
|
||||||
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "netinfo") == 0) {
|
||||||
|
sendNetInfo(theMessage);
|
||||||
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "netlist") == 0) {
|
||||||
|
sendNetList();
|
||||||
|
} else {
|
||||||
|
/* fprintf(stdout, "Request: %s\n", xPL_getMessageNamedValue(theMessage, "request")); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdownHandler(int onSignal) {
|
||||||
|
xPL_setServiceEnabled(telldusService, FALSE);
|
||||||
|
xPL_releaseService(telldusService);
|
||||||
|
xPL_shutdown();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendDevInfo(xPL_MessagePtr msg) {
|
||||||
|
xPL_MessagePtr message = NULL;
|
||||||
|
Bool found = FALSE, deviceCount = tdGetNumberOfDevices();
|
||||||
|
int deviceId = 0, methods = 0, i = 0, lastSentCommand, level = 0;
|
||||||
|
char *name, buffer[12], *value;
|
||||||
|
|
||||||
|
xPL_strToInt(xPL_getMessageNamedValue(msg, "device"), &deviceId);
|
||||||
|
for( i = 0; i < deviceCount; ++i ) {
|
||||||
|
if (tdGetDeviceId(i) == deviceId) {
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||||
|
xPL_setSchema(message, "lighting", "devinfo");
|
||||||
|
|
||||||
|
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
||||||
|
xPL_setMessageNamedValue(message, "device", xPL_getMessageNamedValue(msg, "device"));
|
||||||
|
|
||||||
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0 && found == TRUE) {
|
||||||
|
lastSentCommand = tdLastSentCommand(deviceId, TELLSTICK_TURNON | TELLSTICK_TURNOFF | TELLSTICK_DIM);
|
||||||
|
if (lastSentCommand == TELLSTICK_TURNON) {
|
||||||
|
level = 100;
|
||||||
|
} else if (lastSentCommand == TELLSTICK_DIM) {
|
||||||
|
value = tdLastSentValue(deviceId);
|
||||||
|
level = atoi(value);
|
||||||
|
free(value);
|
||||||
|
level = round((float)level / 255.0 * 100.0);
|
||||||
|
if (level > 100) {
|
||||||
|
level = 100;
|
||||||
|
} else if (level < 0) {
|
||||||
|
level = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
level = 0;
|
||||||
|
}
|
||||||
|
methods = tdMethods(deviceId, TELLSTICK_TURNON | TELLSTICK_TURNOFF | TELLSTICK_DIM);
|
||||||
|
name = tdGetName(deviceId);
|
||||||
|
sprintf(buffer, "1,%s,0,%i", (methods & TELLSTICK_DIM ? "true" : "false"), level);
|
||||||
|
xPL_setMessageNamedValue(message, "status", "ok");
|
||||||
|
xPL_setMessageNamedValue(message, "name", name );
|
||||||
|
xPL_setMessageNamedValue(message, "report-on-manual", "false" );
|
||||||
|
xPL_setMessageNamedValue(message, "channel-count", "1" );
|
||||||
|
xPL_setMessageNamedValue(message, "primary-channel", "1" );
|
||||||
|
xPL_setMessageNamedValue(message, "channel", buffer );
|
||||||
|
xPL_setMessageNamedValue(message, "scene-count", "0" );
|
||||||
|
|
||||||
|
free(name);
|
||||||
|
} else {
|
||||||
|
xPL_setMessageNamedValue(message, "status", "not-found");
|
||||||
|
}
|
||||||
|
|
||||||
|
xPL_sendMessage(message);
|
||||||
|
|
||||||
|
xPL_releaseMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendDevList(xPL_MessagePtr msg) {
|
||||||
|
int deviceCount = 0, i;
|
||||||
|
char deviceList[128];
|
||||||
|
xPL_MessagePtr message = NULL;
|
||||||
|
|
||||||
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||||
|
xPL_setSchema(message, "lighting", "devlist");
|
||||||
|
|
||||||
|
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
||||||
|
|
||||||
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0) {
|
||||||
|
xPL_setMessageNamedValue(message, "status", "ok");
|
||||||
|
deviceCount = tdGetNumberOfDevices();
|
||||||
|
for( i = 0; i < deviceCount; ++i ) {
|
||||||
|
if (i == 0) { /* First */
|
||||||
|
strcpy(deviceList, xPL_intToStr(tdGetDeviceId(i)));
|
||||||
|
} else {
|
||||||
|
strcat(deviceList, ",");
|
||||||
|
strcat(deviceList, xPL_intToStr(tdGetDeviceId(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xPL_setMessageNamedValue(message, "device-count", xPL_intToStr(deviceCount) );
|
||||||
|
xPL_setMessageNamedValue(message, "device", deviceList );
|
||||||
|
} else {
|
||||||
|
xPL_setMessageNamedValue(message, "status", "not-found");
|
||||||
|
}
|
||||||
|
|
||||||
|
xPL_sendMessage(message);
|
||||||
|
|
||||||
|
xPL_releaseMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendGatewayInfo() {
|
||||||
|
xPL_MessagePtr message = NULL;
|
||||||
|
|
||||||
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||||
|
xPL_setSchema(message, "lighting", "gateinfo");
|
||||||
|
|
||||||
|
xPL_setMessageNamedValue(message, "status", "ok");
|
||||||
|
xPL_setMessageNamedValue(message, "protocol", "TELLDUS");
|
||||||
|
xPL_setMessageNamedValue(message, "description", "xPL to Telldus TellStick gateway");
|
||||||
|
xPL_setMessageNamedValue(message, "version", TELLDUS_VERSION);
|
||||||
|
xPL_setMessageNamedValue(message, "author", "Telldus Technologies AB");
|
||||||
|
xPL_setMessageNamedValue(message, "info-url", "http://www.telldus.se");
|
||||||
|
xPL_setMessageNamedValue(message, "net-count", "1");
|
||||||
|
xPL_setMessageNamedValue(message, "preferred-net", "1");
|
||||||
|
xPL_setMessageNamedValue(message, "scenes-ok", "false");
|
||||||
|
xPL_setMessageNamedValue(message, "channels-ok", "false");
|
||||||
|
xPL_setMessageNamedValue(message, "fade-rate-ok", "false");
|
||||||
|
|
||||||
|
/* Broadcast the message */
|
||||||
|
xPL_sendMessage(message);
|
||||||
|
|
||||||
|
xPL_releaseMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendNetInfo(xPL_MessagePtr msg) {
|
||||||
|
xPL_MessagePtr message = NULL;
|
||||||
|
|
||||||
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||||
|
xPL_setSchema(message, "lighting", "netinfo");
|
||||||
|
|
||||||
|
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
||||||
|
|
||||||
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0) {
|
||||||
|
xPL_setMessageNamedValue(message, "status", "ok");
|
||||||
|
xPL_setMessageNamedValue(message, "name", hostname );
|
||||||
|
xPL_setMessageNamedValue(message, "device-count", xPL_intToStr(tdGetNumberOfDevices()) );
|
||||||
|
xPL_setMessageNamedValue(message, "scene-count", "0" );
|
||||||
|
} else {
|
||||||
|
xPL_setMessageNamedValue(message, "status", "not-found");
|
||||||
|
}
|
||||||
|
|
||||||
|
xPL_sendMessage(message);
|
||||||
|
|
||||||
|
xPL_releaseMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendNetList() {
|
||||||
|
xPL_MessagePtr message = NULL;
|
||||||
|
|
||||||
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||||
|
xPL_setSchema(message, "lighting", "netlist");
|
||||||
|
|
||||||
|
xPL_setMessageNamedValue(message, "status", "ok");
|
||||||
|
xPL_setMessageNamedValue(message, "network", "1");
|
||||||
|
|
||||||
|
/* Broadcast the message */
|
||||||
|
xPL_sendMessage(message);
|
||||||
|
|
||||||
|
xPL_releaseMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendGatewayReadyMessage() {
|
||||||
|
xPL_MessagePtr gatewayReadyMessage = NULL;
|
||||||
|
/* Create a message to send */
|
||||||
|
gatewayReadyMessage = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_TRIGGER);
|
||||||
|
xPL_setSchema(gatewayReadyMessage, "lighting", "gateway");
|
||||||
|
|
||||||
|
/* Install the value and send the message */
|
||||||
|
xPL_setMessageNamedValue(gatewayReadyMessage, "report", "gateway-ready");
|
||||||
|
|
||||||
|
/* Broadcast the message */
|
||||||
|
xPL_sendMessage(gatewayReadyMessage);
|
||||||
|
|
||||||
|
xPL_releaseMessage(gatewayReadyMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parseCmdLine will handles command line switches. Valid switches are: */
|
||||||
|
/* -interface x - set interface to use */
|
||||||
|
/* -xpldebug - set debugging and enable xPL debugging */
|
||||||
|
/* -nodaemon - Dosn't disconnect from the console */
|
||||||
|
static Bool parseCmdLine( int *argc, char *argv[]) {
|
||||||
|
int swptr;
|
||||||
|
int newcnt = 0;
|
||||||
|
|
||||||
|
/* Handle each item of the command line. If it starts with a '-', then */
|
||||||
|
/* process it as a switch. If not, then copy it to a new position in */
|
||||||
|
/* the argv list and up the new parm counter. */
|
||||||
|
for(swptr = 0; swptr < *argc; swptr++) {
|
||||||
|
/* If it doesn't begin with a '-', it's not a switch. */
|
||||||
|
if (argv[swptr][0] != '-') {
|
||||||
|
if (swptr != newcnt) argv[++newcnt] = argv[swptr];
|
||||||
|
} else {
|
||||||
|
/* Check for daemon mode */
|
||||||
|
if (!strcmp(argv[swptr],"-nodaemon")) {
|
||||||
|
daemonMode = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Anything left is unknown */
|
||||||
|
fprintf(stderr, "Unknown switch `%s'", argv[swptr] );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set in place the new argument count and exit */
|
||||||
|
*argc = newcnt + 1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print command usage info out */
|
||||||
|
void printUsage(String ourName) {
|
||||||
|
fprintf(stderr, "%s - Telldus TellStick xPL interface\n", ourName);
|
||||||
|
fprintf(stderr, "Copyright (c) 2009, Telldus Technologies AB\n\n");
|
||||||
|
fprintf(stderr, "Usage: %s [-xpldebug] [-nodaemon] [-ip x] [-interface x]\n", ourName);
|
||||||
|
fprintf(stderr, " -xpldebug -- enable xPLLib debugging messagaes\n");
|
||||||
|
fprintf(stderr, " -nodaemon -- don't detach -- run from the console\n");
|
||||||
|
fprintf(stderr, " -interface x -- Use interface named x (i.e. eth0) as network interface\n");
|
||||||
|
fprintf(stderr, " -ip x -- Bind to specified IP address for xPL\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void startServer() {
|
||||||
|
/* Initialze lighting service */
|
||||||
|
|
||||||
|
/* Create a service for us */
|
||||||
|
if (gethostname(hostname, INSTANCE_MAX) != 0) {
|
||||||
|
fprintf(stderr, "Unable to retrieve the hostname");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
telldusService = xPL_createService("telldus", "core", hostname);
|
||||||
|
xPL_setServiceVersion(telldusService, TELLDUS_VERSION);
|
||||||
|
|
||||||
|
/* Add a responder */
|
||||||
|
xPL_addServiceListener(telldusService, lightingRequestHandler, xPL_MESSAGE_COMMAND, "lighting", "request", NULL);
|
||||||
|
xPL_addServiceListener(telldusService, lightingCommandHandler, xPL_MESSAGE_COMMAND, "lighting", "basic", NULL);
|
||||||
|
|
||||||
|
/* Install signal traps for proper shutdown */
|
||||||
|
signal(SIGTERM, shutdownHandler);
|
||||||
|
signal(SIGINT, shutdownHandler);
|
||||||
|
|
||||||
|
/* Enable the service */
|
||||||
|
xPL_setServiceEnabled(telldusService, TRUE);
|
||||||
|
sendGatewayReadyMessage();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/* Let XPL run */
|
||||||
|
xPL_processMessages(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, String argv[]) {
|
||||||
|
|
||||||
|
/* Parse command line parms */
|
||||||
|
if (!xPL_parseCommonArgs(&argc, argv, FALSE)) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start xPL up */
|
||||||
|
if (!xPL_initialize(xPL_getParsedConnectionType())) {
|
||||||
|
fprintf(stderr, "Unable to start xPL");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Hub command arguments */
|
||||||
|
if (!parseCmdLine(&argc, argv)) {
|
||||||
|
printUsage(argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemonMode) {
|
||||||
|
switch (fork()) {
|
||||||
|
case 0: /* child */
|
||||||
|
/* No io in child mode */
|
||||||
|
close(fileno(stdin));
|
||||||
|
close(fileno(stdout));
|
||||||
|
close(fileno(stderr));
|
||||||
|
setpgrp();
|
||||||
|
|
||||||
|
startServer();
|
||||||
|
break;
|
||||||
|
case -1: /* error */
|
||||||
|
fprintf(stderr, "Unable to spawn daemon, %s (%d)\n", strerror(errno), errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startServer();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue