Luup Somfy Walkthrough

From MiOS
(Difference between revisions)
Jump to: navigation, search
(New page: The documentation (see: [http://www.blindshademotors.com/documents/accessories-special-applications/rs232-to-rts-compatability.pdf]) explains that you talk to the controller using RS232 96...)
 
Line 47: Line 47:
 
Open D_TestSerial.xml and re-save it as a different name, such as D_SomfyBlinds.xml.  Change the xml field deviceType to "urn:somfy-com:device:blinds:1" or use your own domain name instead of somfy-com.  Change friendlyName to "Somfy Blind Controller", manufacturer to "Somfy", manufacturerURL to "somfy.com", modelDescription to "16 port RS232 to Somfy blind interface", modelName to "1810686" (the Somfy part number).  modelURL and serialNumber and UPC aren't really important so you can just remove them.
 
Open D_TestSerial.xml and re-save it as a different name, such as D_SomfyBlinds.xml.  Change the xml field deviceType to "urn:somfy-com:device:blinds:1" or use your own domain name instead of somfy-com.  Change friendlyName to "Somfy Blind Controller", manufacturer to "Somfy", manufacturerURL to "somfy.com", modelDescription to "16 port RS232 to Somfy blind interface", modelName to "1810686" (the Somfy part number).  modelURL and serialNumber and UPC aren't really important so you can just remove them.
  
Remove all the tags in 'servicelist' and copy/paste the service for SwitchPower from D_BinaryLight1.xml into the servicelist tag.  You can leave out the controlURL and eventSubURL tags because the Luup engine will replace them anyway.  The servicelist should now look like this:
+
Remove all the tags in 'servicelist'.
 
+
    <serviceList>
+
      <service>
+
        <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>
+
        <serviceId>urn:upnp-org:serviceId:SwitchPower1</serviceId>
+
        <SCPDURL>S_SwitchPower1.xml</SCPDURL>
+
      </service>
+
    </serviceList>
+
  
 
Change the filename in the ''implementationFile'' tag from I_TestSerial.xml to I_SomfyBlinds.xml.
 
Change the filename in the ''implementationFile'' tag from I_TestSerial.xml to I_SomfyBlinds.xml.
Line 86: Line 78:
  
 
2.  Assuming you do see the line '51' log entry showing that the Luup engine is trying to send data, you may want to check the serial port itself.  You can go back to the 'serial port configuration' and remove the 'Somfy blind' device from the serial port so the Luup engine won't open the port.  Make a note of the network ip and port for the serial port.  Click 'Save' to save your changes.  Now from a command prompt run: ''telnet [ip] [port]''.  If you don't have telnet, open another putty session and click the 'telnet' radio box, put in the ip address and port and click 'open'. You should now be able to type the commands in the telnet session: ''!01U'' and see the blinds work.  If it still doesn't work, try connecting the blinds directly to your PC and using a terminal program, like Hyperterminal, to talk directly to the serial port and confirm the connections are ok.
 
2.  Assuming you do see the line '51' log entry showing that the Luup engine is trying to send data, you may want to check the serial port itself.  You can go back to the 'serial port configuration' and remove the 'Somfy blind' device from the serial port so the Luup engine won't open the port.  Make a note of the network ip and port for the serial port.  Click 'Save' to save your changes.  Now from a command prompt run: ''telnet [ip] [port]''.  If you don't have telnet, open another putty session and click the 'telnet' radio box, put in the ip address and port and click 'open'. You should now be able to type the commands in the telnet session: ''!01U'' and see the blinds work.  If it still doesn't work, try connecting the blinds directly to your PC and using a terminal program, like Hyperterminal, to talk directly to the serial port and confirm the connections are ok.
 +
 +
==Step 6: Create the child devices for the blinds ==
 +
 +
In Luup, when you have an interface device which is able to control multiple devices this is represented as a tree where the interface is a 'virtual' device, that probably doesn't implement any actions itself, and multiple 'child devices' under the interface device for each device the interface can control.  The Somfy Blind controller is such a device because the 1 interface can control 16 blinds.  If it only controlled 1 blind, we wouldn't need to implement the parent/multiple child architecture, because we would have just 1 device which implemented the blind functions.  But we want up to 16 different devices for each of the 16 blinds the device can control.
 +
 +
The way to implement multiple children is with the 'Reporting child devices' commands documented in [[Luup_Lua_extensions]].  This is how a parent device, in this case the Somfy blind interface, reports to the Luup engine what child devices it has and what ID number it will use internally to keep track of each one.  Every device in Luup has an "ID" value which has no meaning to the Luup engine itself, but which is used by parent devices to keep track of the children.  Many interface devices have a way to get from them the list of child devices so the parent can manage the children automatically.  The Somfy doesn't.  So we have 2 choices: 1) Just automatically report 16 child devices since the interface supports 16 devices, or 2) Let the user indicate which Somfy blind numbers he has and report just those child devices.  The advantage of #1 is that it's very simple, but the drawback is that the user will see 16 blinds in his home, even if he only has 1.  So, we will do it with #2.  The first question is where to let the user store the list of blind numbers that are active.  The usual way to store this information is to create a UPnP service which contains variables for all the various parameters the user should specify to configure the device.  Then Vera's UI will show this to the user and he can fill in the blanks.  In this case, that's a lot of work to get only 1 parameter: a list of device numbers.  As explained already, Vera already has a tag called "ID" that is easily editable for every device anyway, and this "ID" is user defined.  We will use the "ID" field for the child devices, the blinds, to identify them (ie 1-16), but we've got no use for the "ID" tag in the parent device, the interface device we just created.  So, rather than creating a whole UPnP service just to have 1 variable, we'll put a note in the comments for this device that after adding the interface the user can specify a comma separated list of the actual blind numbers he is using in the "ID" for the device.  If the field is blank or not specified, then we'll just go ahead and create all 16 devices.
 +
 +
The Lua code to do this will be in a 'startup' function which the Luup engine calls automatically whenever it's initialized.  So in the implementation file, in the 'functions' add this:
 +
 +
function lug_startup(lul_device)
 +
  lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
 +
end
 +
 +
And in the 'startup' tag put: ''lug_startup''  The name lug_startup is arbitrary, it can be anything you want.  Now be sure your ssh window is watching the log with ''tail -f LuaUPnP.log | grep '^01\|^5' ''.  Click 'go' in the 'Luup files' upload web tab you left open to upload your changes.  You should the Somfy blind log entry above.
 +
 +
Now we'll add the Lua code to iterate through all the blinds and create the devices.  If you want to debug your Lua script before saving it, go to the 'Test Luup code' window and put this in:
 +
 +
function lug_startup(lul_device)
 +
  lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
 +
end
 +
lug_startup(123)
 +
 +
where 123 should be your actual device number for the device.  The Lua code in ''function lug_startup'' will cause the lug_startup function to be updated when you click 'go', and since ''lug_startup(123)'' is not inside a function, it's executed when you click 'go'.  Note that any functions you create in the 'Test Luup Code' window will still stay in the Luup engine until you reload the Luup engine.  So if you type in the code box:
 +
 +
  function some_test()
 +
    lu_log("some_test")
 +
  end
 +
 +
click 'go', nothing will get logged.  If you then erase the code box and type: ''some_test()'' when you click 'go', you'll see "some_test" in the log.  If you want to update the some_test function, and run it at the same time, do:
 +
 +
  function some_test()
 +
    lu_log("some_test2")
 +
  end
 +
  some_test()
 +
 +
Now when you click 'go', you'll see "some_test2" be logged.  So we'll create a simple startup that creates all 16 blinds by putting this in the Test Luup code window:
 +
 +
function lug_startup(lul_device)
 +
  lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
 +
  lu_chdev_start()
 +
  for(i in "01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16")
 +
    lu_chdev_append()
 +
    lu_log("Creating somfy blind #" .. i)
 +
  end
 +
  lu_chdev_sync
 +
end
 +
lug_startup(123)
 +
 +
Before you click 'go', restart your tail in the ssh window with: ''tail -f LuaUPnP.log | grep '^5\|^01\|^03\|^09\|^11' because the 03 logs indicate when the Luup engine stops and restart, the 09 logs show us when devices are created/deleted, and the 11 logs show when the child device functions are calls.  Now when you click 'go', you should see in the logs ''Child_Devices::AddChild'' is called 16 times, and then 16 times ''Child_Devices::ProcessChildDevice created device''.  You should also see lines starting with '03' that show the Luup engine is reloading since new devices were just created.  When it restarts, you'll see 16 new devices in the logs starting with 09.
 +
 +
lu_chdev_start() tells the Luup engine we're going to start listing all our children.  lu_chdev_append() adds each child and lu_chdev_sync() is called when we're done to synchronize the child device list with Luup's database, and create/remove any new/missing devices, and restart the Luup engine if devices were added or removed.  See: [[Luup_Lua_extensions]]
 +
 +
Now if you click 'go' again, you'll see 16 logs for ''Child_Devices::AddChild'', but no devices will be created or removed because the 16 devices were already created, and the parent/child device lists are still in sync.
 +
 +
Next, we'll update our Lua code to only create child devices that are within the ID.  To make our coding easier, we'll document in the notes for the user than when specifying the list of blinds in the "ID" he must use 01,02, etc., rather than 1,2, etc. because by storing all child devices as 2 digits, we can do a simple search without having to actually parse the ID.  In other words, if we want to know if blind #1 is active, we can safely search the ID for 01 and know that it will only match if blind #1 is active.  If the user stored single digit blind numbers, like ''5,6,11'' then searching for '1' would give us a false positive and we'd need to write more Lua code to break the list apart.  This also makes it easier to send the blind commands because the Somfy protocol says the blind number must be 2 digits, so we won't need to pad the ID's with 0 for the Somfy device.  This is why we did the for loop with 16 text strings, instead of the simpler for(i in 1 to 16), which would have given us normal, non-zero-padded numbers.
 +
 +
Click '+' next to the Somfy blind, click 'Advanced' and in the ID enter: '02,07,13'.  Now in the 'Test Luup code' window enter:
 +
 +
function lug_startup(lul_device)
 +
  lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
 +
  lu_chdev_start()
 +
  for(i in "01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16")
 +
    if( #lug_device[lul_device].ID>0 and find(lug_device[lul_device].ID,
 +
    lu_chdev_append()
 +
    lu_log("Creating somfy blind #" .. i)
 +
  end
 +
  lu_chdev_sync
 +
end
 +
lug_startup(123)
 +
 +
Now when you click 'go' you'll see the logs indicate devices were removed, and we only have 3 blinds now with ID's 02, 07 and 13.  Since this part of the code is done, you can copy/paste this from the Luup test code window into the implementation.  '''IMPORTANT:''' Be sure the ''lug_startup(123)'' is NOT in your implementation file, or else your lug_startup function will be called twice at each startup: once by the Luup engine with the actual device number, and once when the startup functions are loaded into the Lua engine with your hard-coded number used for testing, which won't necessarily correspond to the real device number.
 +
 +
If you're editing the XML file by hand, you can save your changes and click 'go' in the Luup files upload page in your web browser to upload your changes.
 +
 +
Every time you re-start the Luup engine, such as clicking 'Save', you'll see in the logs this startup sequence.
 +
 +
==Step 7a: Implementation the actions in the web generator ==
 +
 +
--coming soon--
 +
 +
==Step 7b: Implementation the actions in the xml file ==
 +
 +
  <action>
 +
    <serviceId>urn:upnp-org:serviceId:SwitchPower1</serviceId>
 +
    <name>SetTarget</name>
 +
    <run>
 +
      local lul_command = '!' .. lug_device[lul_device].ID .. 'U'
 +
      if( parms.newTargetValue==1 or (parms.newTargetValue==0 and lug_device[lul_device].reverse) ) then
 +
        lul_command = '!' .. lug_device[lul_device].ID .. 'D'
 +
      end
 +
     
 +
      if lu_iop_send(lul_command)==false then
 +
        lu_log("cannot send: " .. tostring(lul_command),1)
 +
        lu_SetCommFailure(true)
 +
        return false
 +
      end
 +
    </run>
 +
  </action>
 +
 +
This provides the implementation or the SetTarget UPnP action, which is what is sent when the user clicks 'on' or 'off' for a light switch, or 'open' or 'close' for blinds.  We store the command to send in the variable lul_command and put the 'local' keyword in front so the variable is only available while the 'SetTarget' action is running.  Without 'local', the variable is 'global', which means that
 +
 +
and copy/paste the service for SwitchPower from D_BinaryLight1.xml into the servicelist tag.  You can leave out the controlURL and eventSubURL tags because the Luup engine will replace them anyway.  The servicelist should now look like this:
 +
 +
    <serviceList>
 +
      <service>
 +
        <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>
 +
        <serviceId>urn:upnp-org:serviceId:SwitchPower1</serviceId>
 +
        <SCPDURL>S_SwitchPower1.xml</SCPDURL>
 +
      </service>
 +
    </serviceList>

Revision as of 01:56, 29 June 2009

The documentation (see: [1]) explains that you talk to the controller using RS232 9600 Baud, 8 Data Bits, 1 Stop Bit, No Parity. The interface supports up to 16 blinds. The communication is one-way only; there are no response codes or incoming data from the blinds when they change manually. Here is the relevant section from the manual.

RS232 Operation
1. Set RS232 communication settings to: 9600 Baud, 8 Data Bits, 1 Stop Bit, No Parity
2. Use the ASCII protocol command string syntax: <!> <2 digit channel number> <Directional Command>
3. The directional commands must be capital letters and are as follows:
  U: UP
  D: DOWN
  S: STOP
4. Examples: Motor 2 Up: !02U
  Motor 5 Down: !05D
  Motor 1 Stop: !01S

Contents

Step 1: SSH into Vera

Since this device is so simple it may not be necessary to debug anything. But we'll do this anyway. You need to give Vera a root password, which is the administrator password to login directly. Do this by either: a) from a command prompt in Windows, Linux or Mac type telnet [ip address of vera] and when you see the root@HomeControl:~# prompt enter: passwd and type in a password twice. Then type exit. Or b) In Vera's web ui click Advanced, Net & Wi-fi and the 'Advanced Configuration' link, and supply the password there. Note, sometimes Windows Vista doesn't have the telnet utility installed, so you have to use step b.

Once you have a root password set, you will no longer be able to use telnet to login to Vera, you must use ssh. The reason you should use ssh to login for debugging, and not telnet, is because some of the useful key sequences, like Ctrl+C, don't work in telnet.

Once you've setup a root password, from a Mac or Linux console type: ssh [ip of vera] From a Windows PC, download putty.exe here: [2]. You don't need to install putty, just put the .exe on your desktop or in a folder. When you run putty.exe, type in Vera's IP address and click 'open'.

When you see login as:, enter: root and then enter your password. Now from the root@HomeControl:# prompt type:

 cd /var/log/cmh
 tail -f LuaUPnP.log

Do something in Vera's web ui and you'll see the logs go. Whenever the system rotates the logs, meaning purges the log files because Vera's memory is limited for storing logs, your tail will end. Press the 'up' arrow and hit 'enter' to display the tail command again and restart it. Press Ctrl + c when you've confirm the logs are working ok.

In Vera's web ui, choose Advanced, Logs, and check 'Verbose logging'. This option will create large logs that have lots of information we may need for debugging. It will stay checked for 24 hours and then automatically turn itself off so you're not creating unnecessarily large log files.

Step 3a: Add your with the web generator tool

 --coming soon.  for now use step 3b.

Step 3b: Add your device by building the XML files by hand

In Vera's setup UI, go to Devices, Luup plugins, click 'Luup files' and download the files:

D_BinaryLight1.xml since there is no UPnP device specification for blinds, and blinds are essentially binary devices that are either up/down, we can implement the up/down using the same service that a light switch uses, and that way any UPnP control point that can control a light switch, will also be able to control blinds.

S_SwitchPower1.xml because when you open D_BinaryLight1.xml, you'll see that in the 'services' section, this is the filename (SCPDURL) for the SwitchPower service.

D_TestSerial.xml because this is a sample serial device we can use as a template.

I_TestSerial.xml because this is a sample implementation for our serial device.

Open D_TestSerial.xml and re-save it as a different name, such as D_SomfyBlinds.xml. Change the xml field deviceType to "urn:somfy-com:device:blinds:1" or use your own domain name instead of somfy-com. Change friendlyName to "Somfy Blind Controller", manufacturer to "Somfy", manufacturerURL to "somfy.com", modelDescription to "16 port RS232 to Somfy blind interface", modelName to "1810686" (the Somfy part number). modelURL and serialNumber and UPC aren't really important so you can just remove them.

Remove all the tags in 'servicelist'.

Change the filename in the implementationFile tag from I_TestSerial.xml to I_SomfyBlinds.xml.

Open I_TestSerial.xml and delete the sample Lua code within the 'actionList' tag. Change the 'protocol' tag in 'settings' from crlf to raw because this device doesn't have any low level particular low level protocol, like terminating blocks of data with a carriage return, etc. Save the file as I_SomfyBlinds.xml.

Back on Vera's setup ui under 'Luup files' you the first 'upload' button to upload D_SomfyBlinds.xml and the 2nd to upload I_SomfyBlinds.xml. Check Restart Luup after upload because the files won't be processed unless we restart the Luup engine, and click 'go'. Now leave your browser tab open at this page so that as we change the implementation file we can just click 'go' without having to select the files again.

In another browser tab go to Vera's device page again and under 'Add device' put the new device filename D_SomfyBlinds.xml in the input box, and choose the room where the blind controller is located, click 'Add device', then click 'save'.

Step 4: Setup the port

Vera talks to serial devices using a serial port proxy that turns the serial port into a network port. This way the serial port can reside anywhere on the network. Here are 3 ways to connect Vera to the Somfy device:

1. Get the UC232R-10 usb->serial adapter here: [3] Connect it to one of Vera's USB ports. In Vera's web ui, click the 'save' button, which, even if the 'save' button is grayed out, causes the Luup engine to re-initialize and scan for new serial ports. Wait 30 seconds.

2. Use any Windows COM port or USB->serial port device. Download Windows_Serial_Proxy and run it as explained there. Wait 30 seconds after running it and it will exit after it has reported the port to the Luup engine.

3. Connect a Global Cache GC-100 to your network. Wait 30 seconds or so for the Luup engine to find it. This should happen automatically.

After you've done 1, 2 or 3, go to Devices, Luup plugins and click "Serial port configuration". The serial port should be on the list. Use the pull-down's to set the serial port options: baud=9600, Data Bits=8, Stop Bits=1, Parity=none. For the 'Use with device', select your Somfy Blind controller. Choose 'Save'.

Step 5: Test the port

First, make note of the device id for your Somfy blinds by clicking '+' next to the device in the device list. Next, go to Devices, Luup Plugins, Test Luup code. In the 'Device number' input box put the device number for the Somfy blinds. This way whatever code we test uses the Lua instance for the Somfy blinds, which will be configured already to use the serial port.

In the 'Code' input box, type: lu_iop_send('!01U') and click 'Go'. That is a command according to the Somfy specs, which should make motor #1 go up. You can try other commands and click 'Go' each time. If everything is working ok, skip to step 6. If it's not working, you will want to do some debugging. Here's some debug things to try:

1. Be sure you checked 'Verbose logging' in Step 1. In your ssh console (ie putty if you're using windows) enter tail -f LuaUPnP.log | grep '^5\|^01' where the | means to send the output through the grep utility, which will filter out only certain lines. The ^ means 'lines that start with'. Line that start with 5 are logs related to Lua, and lines that start with 01 are critical errors. The \| means 'or' for grep. Now go back and click 'go' again in the Test Luup window. Return to the ssh console and you should see a line that starts with 51, which means data sent within Luup, that shows !01U. If you're going to be switching back and forth between the ssh console and web ui to do tests, then before you switch to the web ui, you can either hit 'enter' a few times in the ssh console to add some blank space, or press Ctrl+c and then 'up' followed by 'enter' to restart tail. That way you've created some separation between existing log entries and new ones so you can clearly see what is happening when you click 'go'. If you're not seeing anything, in the Test Luup window add the line lu_log('test somfy') above the lu_iop_send. You should see 'test somfy' get logged when you press 'go'.

2. Assuming you do see the line '51' log entry showing that the Luup engine is trying to send data, you may want to check the serial port itself. You can go back to the 'serial port configuration' and remove the 'Somfy blind' device from the serial port so the Luup engine won't open the port. Make a note of the network ip and port for the serial port. Click 'Save' to save your changes. Now from a command prompt run: telnet [ip] [port]. If you don't have telnet, open another putty session and click the 'telnet' radio box, put in the ip address and port and click 'open'. You should now be able to type the commands in the telnet session: !01U and see the blinds work. If it still doesn't work, try connecting the blinds directly to your PC and using a terminal program, like Hyperterminal, to talk directly to the serial port and confirm the connections are ok.

Step 6: Create the child devices for the blinds

In Luup, when you have an interface device which is able to control multiple devices this is represented as a tree where the interface is a 'virtual' device, that probably doesn't implement any actions itself, and multiple 'child devices' under the interface device for each device the interface can control. The Somfy Blind controller is such a device because the 1 interface can control 16 blinds. If it only controlled 1 blind, we wouldn't need to implement the parent/multiple child architecture, because we would have just 1 device which implemented the blind functions. But we want up to 16 different devices for each of the 16 blinds the device can control.

The way to implement multiple children is with the 'Reporting child devices' commands documented in Luup_Lua_extensions. This is how a parent device, in this case the Somfy blind interface, reports to the Luup engine what child devices it has and what ID number it will use internally to keep track of each one. Every device in Luup has an "ID" value which has no meaning to the Luup engine itself, but which is used by parent devices to keep track of the children. Many interface devices have a way to get from them the list of child devices so the parent can manage the children automatically. The Somfy doesn't. So we have 2 choices: 1) Just automatically report 16 child devices since the interface supports 16 devices, or 2) Let the user indicate which Somfy blind numbers he has and report just those child devices. The advantage of #1 is that it's very simple, but the drawback is that the user will see 16 blinds in his home, even if he only has 1. So, we will do it with #2. The first question is where to let the user store the list of blind numbers that are active. The usual way to store this information is to create a UPnP service which contains variables for all the various parameters the user should specify to configure the device. Then Vera's UI will show this to the user and he can fill in the blanks. In this case, that's a lot of work to get only 1 parameter: a list of device numbers. As explained already, Vera already has a tag called "ID" that is easily editable for every device anyway, and this "ID" is user defined. We will use the "ID" field for the child devices, the blinds, to identify them (ie 1-16), but we've got no use for the "ID" tag in the parent device, the interface device we just created. So, rather than creating a whole UPnP service just to have 1 variable, we'll put a note in the comments for this device that after adding the interface the user can specify a comma separated list of the actual blind numbers he is using in the "ID" for the device. If the field is blank or not specified, then we'll just go ahead and create all 16 devices.

The Lua code to do this will be in a 'startup' function which the Luup engine calls automatically whenever it's initialized. So in the implementation file, in the 'functions' add this:

function lug_startup(lul_device)
 lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
end

And in the 'startup' tag put: lug_startup The name lug_startup is arbitrary, it can be anything you want. Now be sure your ssh window is watching the log with tail -f LuaUPnP.log | grep '^01\|^5' . Click 'go' in the 'Luup files' upload web tab you left open to upload your changes. You should the Somfy blind log entry above.

Now we'll add the Lua code to iterate through all the blinds and create the devices. If you want to debug your Lua script before saving it, go to the 'Test Luup code' window and put this in:

function lug_startup(lul_device)
 lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
end
lug_startup(123)

where 123 should be your actual device number for the device. The Lua code in function lug_startup will cause the lug_startup function to be updated when you click 'go', and since lug_startup(123) is not inside a function, it's executed when you click 'go'. Note that any functions you create in the 'Test Luup Code' window will still stay in the Luup engine until you reload the Luup engine. So if you type in the code box:

 function some_test()
   lu_log("some_test")
 end

click 'go', nothing will get logged. If you then erase the code box and type: some_test() when you click 'go', you'll see "some_test" in the log. If you want to update the some_test function, and run it at the same time, do:

 function some_test()
   lu_log("some_test2")
 end
 some_test()

Now when you click 'go', you'll see "some_test2" be logged. So we'll create a simple startup that creates all 16 blinds by putting this in the Test Luup code window:

function lug_startup(lul_device)
  lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
  lu_chdev_start()
  for(i in "01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16")
    lu_chdev_append()
    lu_log("Creating somfy blind #" .. i)
  end
  lu_chdev_sync
end
lug_startup(123)

Before you click 'go', restart your tail in the ssh window with: tail -f LuaUPnP.log | grep '^5\|^01\|^03\|^09\|^11' because the 03 logs indicate when the Luup engine stops and restart, the 09 logs show us when devices are created/deleted, and the 11 logs show when the child device functions are calls. Now when you click 'go', you should see in the logs Child_Devices::AddChild is called 16 times, and then 16 times Child_Devices::ProcessChildDevice created device. You should also see lines starting with '03' that show the Luup engine is reloading since new devices were just created. When it restarts, you'll see 16 new devices in the logs starting with 09.

lu_chdev_start() tells the Luup engine we're going to start listing all our children. lu_chdev_append() adds each child and lu_chdev_sync() is called when we're done to synchronize the child device list with Luup's database, and create/remove any new/missing devices, and restart the Luup engine if devices were added or removed. See: Luup_Lua_extensions

Now if you click 'go' again, you'll see 16 logs for Child_Devices::AddChild, but no devices will be created or removed because the 16 devices were already created, and the parent/child device lists are still in sync.

Next, we'll update our Lua code to only create child devices that are within the ID. To make our coding easier, we'll document in the notes for the user than when specifying the list of blinds in the "ID" he must use 01,02, etc., rather than 1,2, etc. because by storing all child devices as 2 digits, we can do a simple search without having to actually parse the ID. In other words, if we want to know if blind #1 is active, we can safely search the ID for 01 and know that it will only match if blind #1 is active. If the user stored single digit blind numbers, like 5,6,11 then searching for '1' would give us a false positive and we'd need to write more Lua code to break the list apart. This also makes it easier to send the blind commands because the Somfy protocol says the blind number must be 2 digits, so we won't need to pad the ID's with 0 for the Somfy device. This is why we did the for loop with 16 text strings, instead of the simpler for(i in 1 to 16), which would have given us normal, non-zero-padded numbers.

Click '+' next to the Somfy blind, click 'Advanced' and in the ID enter: '02,07,13'. Now in the 'Test Luup code' window enter:

function lug_startup(lul_device)
  lu_log("Somfy blind #" .. lul_device .. " starting up with ID " .. lug_device[lul_device].ID)
  lu_chdev_start()
  for(i in "01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16")
    if( #lug_device[lul_device].ID>0 and find(lug_device[lul_device].ID,
    lu_chdev_append()
    lu_log("Creating somfy blind #" .. i)
  end
  lu_chdev_sync
end
lug_startup(123)

Now when you click 'go' you'll see the logs indicate devices were removed, and we only have 3 blinds now with ID's 02, 07 and 13. Since this part of the code is done, you can copy/paste this from the Luup test code window into the implementation. IMPORTANT: Be sure the lug_startup(123) is NOT in your implementation file, or else your lug_startup function will be called twice at each startup: once by the Luup engine with the actual device number, and once when the startup functions are loaded into the Lua engine with your hard-coded number used for testing, which won't necessarily correspond to the real device number.

If you're editing the XML file by hand, you can save your changes and click 'go' in the Luup files upload page in your web browser to upload your changes.

Every time you re-start the Luup engine, such as clicking 'Save', you'll see in the logs this startup sequence.

Step 7a: Implementation the actions in the web generator

--coming soon--

Step 7b: Implementation the actions in the xml file

 <action>
   <serviceId>urn:upnp-org:serviceId:SwitchPower1</serviceId>
   <name>SetTarget</name>
   <run>
     local lul_command = '!' .. lug_device[lul_device].ID .. 'U'
     if( parms.newTargetValue==1 or (parms.newTargetValue==0 and lug_device[lul_device].reverse) ) then
       lul_command = '!' .. lug_device[lul_device].ID .. 'D'
     end
     
     if lu_iop_send(lul_command)==false then
       lu_log("cannot send: " .. tostring(lul_command),1)
       lu_SetCommFailure(true)
       return false
     end
   </run>
 </action>

This provides the implementation or the SetTarget UPnP action, which is what is sent when the user clicks 'on' or 'off' for a light switch, or 'open' or 'close' for blinds. We store the command to send in the variable lul_command and put the 'local' keyword in front so the variable is only available while the 'SetTarget' action is running. Without 'local', the variable is 'global', which means that

and copy/paste the service for SwitchPower from D_BinaryLight1.xml into the servicelist tag.  You can leave out the controlURL and eventSubURL tags because the Luup engine will replace them anyway.  The servicelist should now look like this:
   <serviceList>
     <service>
       <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>
       <serviceId>urn:upnp-org:serviceId:SwitchPower1</serviceId>
       <SCPDURL>S_SwitchPower1.xml</SCPDURL>
     </service>
   </serviceList>
Personal tools