HowToWriteANewDevice

From ago control wiki
Jump to: navigation, search
[22:03:56] <hari> this is not the most pretty but should be straightforward to understand: http://www.agocontrol.com/trac/browser/agocontrol/agocontrol/devices/agoapc/agoapc.py
[22:04:08] <hari> Trellian: let me just elaborate a bit on it and things will become much clearer for you
[22:04:18] <hari> Trellian: it will only take 5 minutes
[22:04:19] <Trellian> hari: sure
[22:04:30] <Trellian> that i have :)
[22:04:31] <hari> lines 11-13 import the qpid stuff
[22:04:50] <hari> 32-50 load global settings from the config ini
[22:04:58] <hari> like the broker addr, username, and such
[22:05:22] <hari> 83-87 just allow command line specification of these settings
[22:05:47] <hari> 101-106 load a python pickle file
[22:06:14] <hari> it is a "uuid map" that maps the uuid that is announced to agocontrol back to the internal id of the power outlet on the APC power distribution unit
[22:06:28] <hari> you can use pickle and a dict, but you can also use anything else that can store a mapping
[22:06:34] <hari> like xml, yaml, whatever you prefer
[22:06:49] <hari> 109-113 sets up the qpid sender and receivers to be able to get messages in and out
[22:06:51] <Trellian> so far so good
[22:06:54] <hari> ok
[22:07:14] <hari> 117-193 is just stuff that is specific to the APC PDU, you can ignore that
[22:07:54] <hari> 205-214 is a function that sends out a qpid message to the resolver component to define the name of the device
[22:08:10] <hari> that is just for convenience, so that you know which device is which power outlet in the web admin
[22:08:30] <hari> you can set other names later, that is just used for initial definition, not required
[22:08:35] <Trellian> 197 you read the same pickle twice?
[22:08:53] <hari> Trellian: just seen that, jaeger wrote it and probably did a copy and paste error :-)
[22:08:59] <hari> ignore that
[22:09:03] <Trellian> kk :)
[22:09:12] <hari> 217-236 is a lookup function for the pickle uuid map
[22:09:36] <hari> this maps a local "path" (apc outlet port in this case) to a uuid
[22:09:45] <hari> when no mapping is defined yet, it will generate a new uuid and store that
[22:10:14] <hari> they're stored in the pickle file so that they're persistent
[22:10:34] <hari> 239-248 announces the device to the resolver
[22:10:41] <hari> Trellian: as you can see, it is a very simple message
[22:11:06] <Trellian> indeed
[22:11:08] <hari> just listing the device type, the uuid, an optional product, and a specific subject
[22:11:28] <hari> 250-258 send a state changed event
[22:11:51] <hari> the resolver will save the state so that the web admin and others like the android client can disply it
[22:12:03] <hari> with this event you can update that value
[22:13:30] <hari> Trellian: 301-310 then read the inventory from the APC unit, and uses the reportdevice function we've seen earlier to announce them
[22:13:54] <hari> (the APC this was written for has 8 outlets, so it needs to announce 8 binary switches)
[22:14:13] tlaukkan_pad (~tlaukkanp@a88-115-9-24.elisa-laajakaista.fi) joined the channel.
[22:14:25] <hari> then it immediately sends state changed events so that the inventory in the resolver reflects the real device state
[22:15:00] <hari> then it goes into an endless loop in 319 and constantly fetches messages in 321
[22:15:05] <hari> Trellian: good so far?
[22:15:32] <Trellian> so this device actually represents 8 individual devices in ago?
[22:15:36] <hari> yes
[22:16:00] <hari> Trellian: it represents 8 "switch devices"
[22:16:02] <Trellian> ok, good sofar then
[22:16:39] <hari> Trellian: after receiving a new message in 321, it branches depending on the command in the message
[22:17:00] <hari> when it recieves a "discover" message, it shall announce its devices
[22:17:12] <hari> so it does not only announce them on startup , but also when a discover message comes in
[22:17:40] <Trellian> hari: discover is periodically send by the resolver
[22:17:43] <hari> that is needed when the resolver is restarted or other devices, that were not running when your device got started, want to get an overview of devices
[22:17:43] <Trellian> ?
[22:17:50] <hari> not periodically, only at startup
[22:18:18] <Trellian> makes sense
[22:18:35] <hari> the resolver is an optional component. Some other components depend on it, but it is feasible to run only minimal parts on e.g. a very limited embedded system
[22:18:45] <hari> one could write a special gui that does not rely on the resolver
[22:18:53] <hari> thus you need to respond to the discover command
[22:19:06] <hari> and announce all your "child" devices
[22:19:24] <hari> in 331 it makes sure that the command has an id
[22:19:31] <hari> aeh uuid
[22:20:04] <hari> in 332/333 it checks if the uuid from the message is in the local mapping
[22:20:11] <hari> to determine if this is "our" child device
[22:20:26] <hari> it might belong to some other device interface, like Z-Wave, KNX, or whatever
[22:20:50] <hari> so we need to make sure that it is targeted at one of the devices we handle
[22:20:56] <Trellian> the ACK is for acknowledging proper reception of the command and not that it executed without error?
[22:21:13] <hari> correct
[22:21:36] <hari> parts like the web admin expect that commands are acked with a reply
[22:21:47] <hari> Trellian: then you do your magic
[22:22:19] <hari> in this case, it calls the  set_outlet_state to switch the APC port that belongs to the specific uuid
[22:22:20] <Trellian> hari: what if the command fails?
[22:22:39] <Trellian> hari: let me rephrase
[22:22:40] <hari> Trellian: that would be reflected in the state changed event
[22:22:59] <hari> in 350 and 355 it sends a state change event
[22:23:15] <Trellian> hari: what if the command is not executed properly, can i send an error back?
[22:23:37] <hari> the party that did send the command will get an instant ACK for the command itself, and can then watch for the state changed event to make sure that the state did change properly
[22:24:02] <Trellian> hari: ah ok, so that is the responsibility for the asking party?
[22:24:06] <hari> yes
[22:24:13] tlaukkan_pad (~tlaukkanp@a88-115-9-24.elisa-laajakaista.fi) left IRC. (Quit: Quit)
[22:24:31] <hari> Trellian: you could also defer your ACK until after you did your magic
[22:24:32] <Trellian> nice, saves a lot on plugin complexity i suppose
[22:24:43] <hari> and reply e.g. an ERR instead of ACK
[22:25:00] <hari> but the web admin does not currently honor it, it is happy with any reply
[22:25:08] <Trellian> hehe
[22:25:12] <hari> same for android :-)
[22:25:18] <Trellian> all in due time :)
[22:25:21] <hari> yeah
[22:25:35] <hari> and that is it..
[22:25:39] <Trellian> cool, tbh it doesn't sound that complicated
[22:25:44] <hari> so the message sending via qpid is quite easy
[22:26:05] <hari> Trellian: the most complex part is probably your internal mapping of ago control devicetypes/uuids to your OLA channels :-)
[22:26:26] <Trellian> ye
[22:26:43] <hari> Trellian: do you know KNX?
[22:27:01] <hari> I used an XML mappig file there: http://wiki.agocontrol.com/index.php/KNX#Device_configuration
[22:27:12] <Trellian> hari: only basics that it's bus based, not much more
[22:27:18] <hari> I had to map ago control devices/uuid to KNX GA (group addresses)
[22:27:48] <hari> they're like DMX channels in the sense that you send values to a specific GA for action, so a dimmer has multiple GAs, one for on/off, one for dimming, and so on
[22:27:54] <Trellian> i suppose i could do the same for channles
[22:28:00] <hari> yeah
[22:29:44] <Trellian> nice, thanks for the walkthrough
[22:29:52] <hari> you're more than welcome
[22:29:58] <hari> don't hesitate to ask if you need anything
[22:30:03] <Trellian> hari: might be nice to copy/paste this into a wiki for future reference :)
Personal tools