Add some different xPL implementations done by Telldus

This commit is contained in:
Micke Prag 2012-05-29 14:18:28 +02:00
parent deebf2045e
commit d4b46c71ec
21 changed files with 2285 additions and 0 deletions

371
xpl/data/uml.xmi Normal file
View 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&lt;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
View 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;
}

View 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;
}
}

View 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();
}
}
}

View 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;
}
}

View 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
View file

@ -0,0 +1 @@
__all__ = ["xplmessage", "xpldevice", "xplinstance"]

22
xpl/pyxpl/xpldevice.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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 &timestamp ) {
d->lastHeartBeat = timestamp;
}

38
xpl/qtxpl/xpldevice.h Normal file
View 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 &timestamp );
private:
xPLDevicePrivate *d;
};
#endif // XPLDEVICE_H

226
xpl/qtxpl/xplinstance.cpp Normal file
View 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
View 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
View 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
View 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

View 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

View 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;
}