Domoticz : How to control Somfy Devices



Background

In a previous article, I demonstrated how to control Somfy devices using php and the Somfy API. Now that it's working, we need to identify some useful activities related to this new functionality. Why not begin integrating it into a Home Automation platform like Domoticz? Let's dive into it.

Executing a script from Domoticz

Domoticz is providing a facility to start a script on the push of a button. Let's think at useful cases that mix environmental measures and Somfy activities.

What I have in mind is 2 different scenario :
  1. Create a push button to close/open all blinds in my pergola
  2. Open the roof of the pergola if the temperature exceeds 25°C. If the roof is already open, do nothing. And do nothing at night of course.
Let's work on the first one.

1) Action based on push button

Domoticz offers the ability to create a dummy sensor that does nothing until we tell him to perform some actions. In a previous blog post, we already created a virtual hardware that does nothing and reserved for scripting.

By clicking on Create Virtual Sensors, we can dedicate a switch to perform some custom activities based on a script.


Since the Switch sensor type has been selected, let's navigate to the switch section and edit the virtual sensor.


In this example, the Switch type will be blinds. There are two outstanding fields we need to consider : Open Action and Close Action. This is where the script will be used to send the relevant actions.

So, we need to write two scripts : one to open screens/blinds and one to close them. In the previous article, we already wrote some scripts related to screens. Let's adapt them for the current requirement.

First, the script to open the blinds : 

<?php
include_once 'syFramework.php';

syScreenUp($tahomaPin,$token,"io://20xx-30xx-05xx/16249868");
syScreenUp($tahomaPin,$token,"io://20xx-30xx-05xx/5247014");
syScreenUp($tahomaPin,$token,"io://20xx-30xx-05xx/6245842");
?>

As simple as that ! As you see, there is no need to manage the stop (top or bottom), the system is using the defined value by the limit switch automatically preventing hazardous situations.

Similarly, we need another script to close the blinds : 

<?php
include_once 'syFramework.php';

syScreenDown($tahomaPin,$token,"io://20xx-30xx-05xx/16249868");
syScreenDown($tahomaPin,$token,"io://20xx-30xx-05xx/5247014");
syScreenDown($tahomaPin,$token,"io://20xx-30xx-05xx/6245842");
?>

Next step is to create some sort of executable scripts from the command line - using bash :

#!/bin/bash
cd /home/pi/domoticz/scripts/php
php syCloseScreen.php

And the other one to open blinds : 

#!/bin/bash
cd /home/pi/domoticz/scripts/php
php syOpenScreen.php

Don't forget to make them executable :) 

$ chmod +x syOpenScreen.sh syCloseScreen.sh

Now, we are ready to tell the virtual switch what to execute for opening and closing actions : 


Pay attention to the syntax here, it started with script:/// yes, there are 3 slashes since we are indicating a Linux path.

On the sensor main view, there are 2 buttons : one to open and one to close the blinds. Simply click on them to initiate the two actions defined in the scripts above : 


This was a very simple example to understand the possibilities. Let's check the next one now.

2) Action based on external trigger

Domoticz also allows creation of event based on specific external triggers. Reminder : we need to open the roof just a little bit to allow hot air to leave the inside of the pergola when the temperature exceeds 25°C and if the roof is already closed at daytime and no rain is detected.

Using the Event section, we can create something similar to this Blockly script :
Blockly is not very flexible, so I will not use this option.

Before jumping into this, we need to know the status of the roof. Indeed, if the roof is already open, there is no need to do anything. Also, we need a sensor returning the actual outdoor temperature. I'm assuming I have one already to simplify the exercise.

Let's come back to the Somfy APIs to get the status of a device.

A simple cURL and I can retrieve the status of my roof slats positions.

$ curl -X 'GET''https://gateway-20xx-30xx-05xx.local:8443/enduser-mobile-web/1/enduserAPI/setup/devices/io%3A%2F%2F20xx-30xx-05xx%2F415298/states' -H 'accept: application/json' -H 'Authorization: Bearer 65075d2000000d50afb0'

It returns this :

{ "type": 11, "name": "core:ManufacturerSettingsState", "value": { "current_position": 51200 } }

So, when the roof is fully closed, the current_position equal to 51200. When It is completely opened  the status is 0.

It evolves between 51200 and 0. It is corresponding to the slats position between 0° to 150°.

There is an API command that could be used to specify the required position. Unfortunately, at the time I'm writing these lines, this is not possible to use this command. The controller received it and acknowledge execution, but nothing happens. Seems like a bug?!?

I tried to think at alternate ways to achieve the same objective and I came across 2 options : 
  1. Start moving the slats and check the current position until we reach the desired position
  2. Start moving the slats for a certain amount of time that matches the required position
Option 1 is slow and not efficient since the position is not updated in real time when I'm trying to retrieve current state. I added timers but still. It seems it requires 5 seconds to update the state after moving the slats.

Option 2 seems to be the more efficient but needs some fine tuning to determine the ideal time. In my case 3 seconds seems a good timing.

Optional item to consider : the rain sensor. If it is raining, we do not want to open the roof. So far, I did not managed to read this status on my system. It works with a PriorityLock, if the lock is in place, the roof is ignoring open commands. Something seems to be not working as it should on my side. Once I figured it out, I will update the script. However, it is barely raining when the temperature is >= 25°C in my country, ....

So, between sunrise and sunset, if the temperature is above 25°C, if the roof is closed, open the it a little to allow hot air leaving the space. Outside of these conditions, do nothing.

Let set this into music !

I will create a the script named syAllowAirFlow.php. It is getting status from both Domoticz and the Somfy Tahoma gateway and then eventually, if conditions are met, send the command to open the roof.

Get the roof status

So, if the roof position is 51200, it means the roof is closed. Let's create a test based on this value : 

[...]
$currRoofPos=syGetDeviceState($tahomaPin,$token,"io://20xx-30xx-05xx/415298")[5]->value->current_position;

if($currRoofPos==51200)
[...]

I noticed the roof position is not always at index 5 in the array. I fixed the code to detect the correct position. You'll see that later.

Get the daylight status

To determine if we are during the day, I can ask Domoticz about my local situation. Of course, sunrise and sunset change every day, so better ask a reliable source.

Domoticz provides a specific API endpoint to retrieve this information located at https://<domoticz_ip>/json.htm?type=command&param=getSunRiseSet

I created a function for it :

//--------------------------------------------------------------------
// Function retrieving the sunrise and sunset time for the current day 
//--------------------------------------------------------------------

function dzGetSunRiseSet($domoticzIP)
{
    $api="/json.htm?type=command&param=getSunRiseSet";

    $curl = curl_init($api);

    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($curl, CURLOPT_URL, "https://".$domoticzIP.$api);

    $result = json_decode(curl_exec($curl));
    curl_close($curl);

    return($result);
}

It returns something like this : 

object(stdClass)#2 (13) {
  ["AstrTwilightEnd"]=>
  string(5) "21:20"
  ["AstrTwilightStart"]=>
  string(5) "05:47"
  ["CivTwilightEnd"]=>
  string(5) "20:03"
  ["CivTwilightStart"]=>
  string(5) "07:04"
  ["DayLength"]=>
  string(5) "11:55"
  ["NautTwilightEnd"]=>
  string(5) "20:41"
  ["NautTwilightStart"]=>
  string(5) "06:26"
  ["ServerTime"]=>
  string(19) "2023-09-27 21:41:10"
  ["SunAtSouth"]=>
  string(5) "13:33"
  ["Sunrise"]=>
  string(5) "07:36"
  ["Sunset"]=>
  string(5) "19:31"
  ["status"]=>
  string(2) "OK"
  ["title"]=>
  string(13) "getSunRiseSet"
}

So, by comparing if current time is within the Sunrise and Sunset time, we know if this is the day. And this works anytime of the year !

[...]
    $currTime=date('H:i:s');
    if($currTime>$sunRise and $currTime<$sunSet) ...
[...]

Get the pergola temperature

Next, we need to check the temperature in the pergola, if above 25°C, we need some air ;) We have a device in Domoticz returning this value, we simply query it at https://<domoticz_ip>/json.htm?type=devices&rid=6425.

Something similar is returned (yes, sunrise and sunset are also part of the data !!! I've seen it too late, my routine was already created).

object(stdClass)#2 (16) {
[...]
  ["Sunrise"]=>
  string(5) "07:36"
  ["Sunset"]=>
  string(5) "19:31"
  ["app_version"]=>
  string(6) "2023.2"
  ["result"]=>
  array(1) {
    [0]=>
    object(stdClass)#3 (38) {
[...]
      ["Data"]=>
      string(12) "20.1 C, 13 %"
[...]
  ["title"]=>
  string(7) "Devices"
}

My sensor is returning temp and humidity, so, some string manipulation is required :

$temp=dzGetSensor($domoticzIP,$sensorID);

// Get relevant field
$temp=$temp->result[0]->Data;

// Only need temperature 
$temp=explode(",",$temp)[0];

// remove leading " C" and make sure this is a number
$temp=(float)substr($temp, 0, strlen($temp)-2);

Returning this : 

float(20.1)

We have our next test : 

if($currTemperature>=25)

Now that we have all the tests, we can implement the logic in a complete script : 

[...]

// Check if we are in daytime
if($currTime>$sunRise and $currTime<$sunSet)
{
print("This is day time\n");

        // Check is roof closed
if($currRoofPos==51200)
{
print("Roof is closed\n");

                // Check for the temperature
if($currTemperature>=$maxTemp)
{
    print("It is hot, let's open the roof\n");
                    syRoofOpen($tahomaPin,$token,$$roofAddress);
    sleep($roofTimer);
    syRoofStop($tahomaPin,$token,$$roofAddress);
                }
        }
}

[...]

The full commented script is available on my GitHub repo.

Once the script works, we have to run it from time to time in case of this is getting hot inside the pergola. I'm opting for a cron job running the script every 5 mins. That should be enough.

*/5 * * * * /home/pi/domoticz/scripts/php/syAllowAirFlow.sh

"Et voilĂ  !"

Examples : 

$ php syAllowAirFlow.sh

Starting roof routine...
This is day time.
Roof is closed.
It is not warm enough (17.4°C), let's keep roof closed.

and 

php syAllowAirFlow.sh

Starting roof routine...
This is day time.
Roof is closed.
It is hot (25.6°C), let's open the roof.

The roof in action : 



I hope this helps others to get inspiration and fresh air ;)








Comments

What's hot ?

ShredOS : HDD degaussing with style

Mac OS X : Display images in-line with terminal