Matrix-713
https://www.artila.com/docs/Matrix-713/Matrix-713_Datasheet.pdf
In previous versions of VSCP whenever you did an install all configuration files were replaced with the latest version. This is not true anymore. Now the new version is instead written as a copy with the date of the install appended to it. So if you after a “make install” or a “dpkg -i vscpd” want the latest configs you have to copy the backup to the actual config file and restart the VSCP server.
Files that is handled in this way is
/etc/vscp/vscpd.conf
/srv/vscp/dm.xml
/srv/vscp/simtempdata.txt
/srv/vscp/variables.xml
Also if you are on unstable code you should remove the databases before you start the updated server . Use
rm /srv/vscp/*.sqlite3
for this.
Also note that the web sample code is not installed in the install/update process no more. The process to get this subsystem installed with be described later.
The work with the upcoming 13.0.0 Aluminium release is moving on. As usual a few surprises has turned up adding some weeks to the work but things move forward as expected. Instead of being released before X-mas I now expect it to be out sometime late January next year.
For those of you doing home automation project I can recommend Domoticz and OpenHAB (in that order). Both projects has a huge and active user base constantly adding support for new devices. Much better choices for HA freaks than VSCP will ever be.
I also want to take the opportunity to wish all of you a merry X-mas. This year has been a quite rough time here and that will continue for some time but with the support from many of you I have managed to keep servers active and also had a chance to get some new hardware to play with as well. Thanks for your generosity. I will never forget.
There are a few days more coding for me before I turn of my computer and rest for a couple of days. A good book, some movies and a lot of food is waiting for me and honestly I need the rest. I hope all of you enjoy a few days rest also.
Be hungry, stay foolish
/Ake
Timers. One can wonder what they do in the decision matrix? They even have their own events defined in the CLASS2.VSCP class.
First let us define what a VSCP timer is.
A VSCP timer is a free running 32-bit timer with millisecond resolution. That is they can hold 0xffffffff = 4294967295 milliseconds which mens they will roll over in about 50 days.
There are actions defined to
There is the following internal events defined related to timers
To create and start a timer
<row enable="true" groupid="timers" > <comment> Create timer </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="23" GUID="00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F" /> <action>0x60</action> <param> 1;10;timer1flag;true </param> </row>
Here a timer with id = 1 is created. The timer has an initial time set to 10 seconds. When this timer elapses it will set the variable //timer1flag// to true. The last argument is the reload flag. Here it is set to true so when the time has elapsed the initial value will be loaded again and the timer will start again.
In the example above we could have added “;4” at the end of the parameter which would have the effect that the reload would stop after four runs. Default is thus forever.
When the timer is started a CLASS2.VSCPD, Type = 25 (0x0019) Timer started event is generated. When the ten seconds has gone and the timer elapses the CLASS2.VSCPD, Type = 29 (0x001D) Timer Elapsed event is generated.
We can use either one of these two generated events to do any action periodically like this.
<row enable="true" groupid="timers" > <comment> Handle timer elapsed </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="29" GUID="00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F" /> <action>0x70</action> <param> /srv/vscp/timefile;1;%isoboth: Timer with id=%event.data.int32[0] elapsed %lf </param> </row> <row enable="true" groupid="timers" > <comment> Handle timer elapsed </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="25" GUID="00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F" /> <action>0x70</action> <param> /srv/vscp/timefile;1;%isoboth: Timer with id=%event.data.int32[0] elapsed counter=%event.data.uint32[0]ms %lf </param> </row>
Here some info is just written to a file when the timer is started and when it elapses. But if you want to send an event periodically instead or do other actions this is the way to do it.
You don’t have to give a variable nor a reload flag when you start a timer. If no variable is given (use ;;) it is just ignored. The reload value will be set to false as default value, that is the timer will run only once. As the last parameter you can set the number of times the timer should reload before it should stop. The full documentation is here and here.
One useful use of timers is to handle resend of events. The working is like this
Send the event you expect a reply event from another node.
Can be used for much more of course. Just useful and simple.
The Level I logger and the Level II logger are great tools for logging events in a VSCP based system. Useful also for debugging etc. Another method is to use the execute external program action and execute a script and write to a file there. We have seen this method being used in other howtos. Also while running a JavaScript or a Lua script files can be written.
But…
file writing is also available as an action. It is documented here. This action allows writing or appending a string with output to a named file that is created if it does not exist. With the VSCP escapes a lot of dynamic information can go into this file.
Suppose that we want to log events of a certain type to a file, here CLASS1.DATA, Type=2 A/D values form a specific device. We then write a decision matrix (DM) row
<row enable="true" groupid="" > <comment> Collect A/D values from node X </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID="FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF" /> <filter priority="0" class="15" type="2" GUID="00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F" /> <action>0x70</action> <param> /tmp/addata;1;%isoboth: %measurement.string %lf </param> </row>
will generate output content like this
With the other VSCP escapes and literals you have many options to generate meaningful output.
In a previous howto we looked at how to link server interfaces. Sometimes it is not necessary to establish a full link but just send an event to the rest of the system. A typical example on this can be when an event comes in that signals a special state and you what the system to go perform other steps. Here you can send out the events needed to perform those steps.
There are currently three actions defined for this in the VSCP server
VSCP_DAEMON_ACTION_CODE_SEND_EVENT 0x40/64
This actions sends out a specified event and optionally set a boolean variable to true if the send was successful. The full documentation is here.
If for example you want to send the event CLASS1.INFORMATION, Type=3, ON every second you can use
<row enable="true" groupid="Send event"> <comment> Periodic event Send CLASS1:INFORMATION, Type=3 ON event every second </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="5" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x40</action> <param> 0,20,3,0,,,0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15,0,1,35 </param> </row>
VSCP_DAEMON_ACTION_CODE_SEND_EVENT_CONDITIONAL 0x41/65
This action works much as the previous action. The difference is that it just send the event if a named VSCP remote variable is true. The full documentation is here.
If you like in the example above want to send the event CLASS1.INFORMATION, Type=3, ON every second you can use
<row enable="true" groupid="Send event conditional" > <comment> Create variable that hold flag for sent event when the server is started ( CLASS2.VSCPD, Type=23 ). </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="23" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x50</action> <param> bsent;bool;false;0;0x777;false </param> </row> <row enable="true" groupid="Send event conditional" > <comment> Create variable that hold flag send conditional event when the server is started ( CLASS2.VSCPD, Type=23 ). </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="23" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x50</action> <param> bevent;bool;false;0;0x777;false </param> </row> <row enable="true" groupid="Send event conditional"> <comment> Send event conditional Send CLASS1:INFORMATION, Type=3 ON event </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="5" GUID="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x41</action> <param> bevent;0,20,3,0,,,0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15,0,1,35;bsent </param> </row>
The difference from the previous example is the introduction of the bEvent remote variable. This variable is initialized to false so before it is set to true no events will be sent. We can look at the variable sin the admin web interface
Setting it to true
make the action trigger and the event is sent once a second while the bEvent variable is set to true.
The last send event action send one or more events from a file instead of having them specified in the action parameter. This makes it possible to send several events from one trigger. A typical scenario could be to trigger on button press and set a scene by presetting lamps and other things which will be set by the sent out list of events,
This action is fully specified here. The file for the events to send out is XML based. Apart from that it should be easy to set up from the documentation.
The events defined here in a file called sendevents simulate setting a scenario.
<events> <event> <!-- CLASS1.CONTROL, Type=5 TurnOn Turn on lamps in zone=1, subzon=0 --> <head>0</head> <class>30</class> <type>5</type> <guid>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</guid> <data>0,1,0</data> </event> <event> <!-- CLASS1.CONTROL, Type=5 TurnOn Turn on lamps in zone=1, subzon=0 --> <head>0</head> <class>30</class> <type>5</type> <guid>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</guid> <data>0,1,2</data> </event> <event> <!-- CLASS1.CONTROL, Type=5 TurnOn Turn on lamps in zone=1, subzon=22 --> <head>0</head> <class>30</class> <type>5</type> <guid>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</guid> <data>0,1,22</data> </event> <event> <!-- CLASS1.CONTROL, Type=5 TurnOn Turn on lamps in zone=1, subzon=240 --> <head>0</head> <class>30</class> <type>5</type> <guid>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</guid> <data>0,1,240</data> </event> <event> <!-- CLASS1.CONTROL, Type=6 TurnOff Turn off head light lamps in zone=1, subzon=1 --> <head>0</head> <class>30</class> <type>6</type> <guid>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</guid> <data>0,1,1</data> </event> <event> <!-- CLASS1.CONTROL, Type=20 Dim lamp(s) Dim lamps in zone=1, subzon=0 at 30% --> <head>0</head> <class>30</class> <type>20</type> <guid>00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00</guid> <data>30,1,0</data> </event> </events>
A DM that sets this scenario every minute looks like this
<?xml version = "1.0" encoding = "UTF-8" ?> <dm> <row enable="true" groupid="Send events from file" > <comment> Send events in list sendevents when the server is started ( CLASS2.VSCPD, Type=23 ). </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="6" GUID="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x42</action> <param> /srv/vscp/sendevents </param> </row> </dm>
And running it we see in VSCP works that the events get sent
You can find sample files for tests here.
In another Howto we looked at the measurement compares that are available in the decision matrix (DM) record (VSCP HOWTO: COMPARE VALUES WITHOUT CODING). Here we will look at an action that work in a similar equal manner.
The check measurement action
VSCP_DAEMON_ACTION_CODE_CHECK_MEASUREMENT
is defined to make it possible to check a measurement against a literal value and just as we described in the howto about the check variable actions it stores the logical outcome of the compare in a boolean remote variable.
Also here equal to, less than, greater than etc is available. A typical parameter row can look like this
0;0;99.5;gt;flag
This says that if a measurement comes in that have a value that is greater than 99.5 the remote variable “flag” will be set to true. In all other cases “flag” will be set to “false”. The “0;0” that is the first two values of the parameter line is unit and sensor index. In this case the measurement therefore must have unit=0 and sensor index = 0 as well for the test to be evaluated at all.
A complete example is available in the documentation of the action. You can find pre written samples here.
As a note. Instead of a literal value for the compare you can use another variable. The parameter above can be rewritten
0;0;%variable:[critical_value];gt;flag
and instead of the literal “99.5” the value of the remote variable 99.5 is used for the compare. VSCP DM escapes are evaluated before an action is carried out. There is many of them and they can be very useful when you want to make decision matrix rows act in a more dynamic way without go so far as to use full JavaScript or Lua. You can read more about the VSCP DM escapes here.
It isn’t harder than that actually.
A common operation handling flowing data and measurements is to compare results and the decision matrix (DM) has plenty of functionality built-in for this. Here we will look at three of the actions available for this.
They are
Check variable, set variable VSCP_DAEMON_ACTION_CODE_CHECK_VARIABLE
Check variable, set to true VSCP_DAEMON_ACTION_CODE_CHECK_VARIABLE_TRUE
Check variable, set to false VSCP_DAEMON_ACTION_CODE_CHECK_VARIABLE_FALSE
What they all do is to compare (less than, greater than equal etc) a literal value with the content of a remote variable and they
This action check the value of a variable against a literal and the set the named boolean remote variable to the outcome of the logic operation. So
3.14;eq;pi;myflag
will set the remote variable myflag to true if the remote variable pi is equal to 3.14 (false otherwise) and
32;lt;temp;alarm
will set the boolean remote variable alarm to true when the remote variable alarm have a value that is greater than 32 and to false otherwise.. The last will look like this in its complete form
<row enable="true" groupid="Variable compare" > <comment> Test the variables tamp if its greater than 32 every second </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="5" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x58</action> <param> 32;lt;temp;alarm </param> </row>
This is just a variant of the above. Instead of the result of the logical compare true is always stored when the calculated result is true.
So the example above
32;lt;temp;alarm
will no actually do the same as before. If the result is true it stores true and false if not.
Another variant of the same. Instead of the result of the logical compare false is always stored when the calculated result is true.
So for the example above
32;lt;temp;alarm
alarm will be false when temp is greater than 32 and vice versa.
————————————————————————————
Some ready-made test code is available here.
.
Quite often one want to store min and max for measurement values So of course you can do that with the VSCP server just by adding a row to the decision matrix.
The first thing you need is a remote variable to store the min/max in. You can add this remote variable to the variable xml file so it is created when the system starts or add it as a persistent variable to the database. Another way is to create the variable when the server starts right is the DM. We use the last method here as it is makes things clearer in this how-to.
You can create a remote variable minimum and another maximum with the following two DM rows which triggers on the CLASS2.VSCPD, Type=23 Starting up which is feed to the DM once when the VSCP server is started. .
<row enable="true" groupid="Min/max" > <comment> Create variable that hold min when the server is started ( CLASS2.VSCPD, Type=23 ). </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="23" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x50</action> <param> minimum;float;false;0;0x777;9999999;BASE64:test min </param> </row> <row enable="true" groupid="Min/max" > <comment> Create variable that hold min when the server is started ( CLASS2.VSCPD, Type=23 ). </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="65535" type="23" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x50</action> <param> maximum;float;false;0;0x777;-999999;BASE64:test max </param> </row>
Here the minimum variable is created as a non-persistent variable (it will not hold its value between sessions), it is created as a float and initiated to a “very high” value (9999999), The maximum variable is also created as a float and initiated to a “very low” number (-999999).
You can read more about the store remote variable action here.
The values for the minimum and maximum variables is selected so that minimum is initiated to a value that is higher than what is expected to be a lowest value that will be received by the system and the same for the maximum but the other way around.
So no we have the two variables. Suppose we now want to check the maximum and minimums for a temperature. This means that we will look for a measurement event with type = 6 temperature. I write “measurement event” here as they come in a couple of flavors. A DM row like the following will handle the collection of minimum data
<row enable="true" groupid="Min/max" > <comment> Test for minimum </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="10" type="6" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x71</action> <param> minimum;1;1 </param> </row>
Here we filter on CLASS1.MEASUREMENT, Type=6 temperature (class=10, type=6) from any sensor (we normally should have selected on by entering a GUID for it). The action 0x71 is the
VSCP_DAEMON_ACTION_CODE_STORE_MIN
and it will store the temperature value of the incoming VSCP event if it is lower than the value currently stored in the remote variable minimum. The 1,1 after the variable name in the parameter says that the measurement should have unit=1 (Celsius in this case) and originate from sensor with index=1 on the remote node,
For the maximum the DM row looks like
<row enable="true" groupid="Min/max" > <comment> Test for maximum </comment> <mask priority="0" class="0xFFFF" type="0xFFFF" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <filter priority="0" class="10" type="6" GUID=" 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" /> <action>0x72</action> <param> maximum;1;1 </param> </row>
The functionality is the same except that the
VSCP_DAEMON_ACTION_CODE_STORE_MAX
action is used here which compares the names variable for a highest value instead of a lowest value.
That it. We now have to variables maximum and minimum that holds the maximum and minimum values for the temperature. We can read (and write) this value in all the interfaces, tcp/op, websocket, mqtt, REST etc and use it for other calculations or present it in a UI. With websocket this presentation is actual trivial using one of the ready-made widgets.
Also not that this work s for all measurement units (that is all SI defined and derived units) in the same way. No coding needed.
One last thing. Suppose you want to daily maximum/minimum instead of an all time maximum/minimum. Easy
Add a DM row that triggers on
CLASS2.VSCPD, Type=9 Midnight
and store the “very low”/”very high” value to the minimum. It is harder than that. In the same way you can do this on a weekly, monthly etc basis.
You can also use the escapes to create a more dynamic variable that store the daily minimum/maximum. Try a store in variable
minimum-%isodate;float;true;0;0x777;%variable:[minimum]
which is set to trigger just before midnight. What you get here is a remote variable minimum-YYMMDD where YYMMDD is the current date that is persistent and holds the value of the minimum remote variable collected for that date.
Try that with the rest..