Laurent Modules and Smart Home (Part 2). Arduino and AMS
This is the second article in a series on integrating KernelChip’s Laurent modules into home automation systems, and in this part we will focus on integrating these modules with the Arduino ecosystem. In the first part of the series, we talked about integration with MajorDoMo, a popular home automation system, and in the third part you will learn how to manage these modules from sketches in the Processing programming language, right from your computer’s desktop.
Where without Arduino? I’m not going to describe the advantages of this platform for a long time, its popularity speaks for itself, so let's immediately get down to the technical details of the interaction between Arduino and Laurent modules. And along the way, we will not forget the Arduino Mega Server system , as a very interesting derivative of the Arduino ecosystem.
For controlling modules over the network, for example, the common Arduino Uno board or the equally popular Arduino Mega board complete with an Ethernet Shield network interface card assembled on the basis of the W5100 chip are suitable. All examples in this article are given for such a combination and have been tested in practice. Everything works reliably and without any problems.
Ethernet Shield based on the W5100 chip
That is, you just have to take the sketch and upload it to your Uno or Mega board, after changing it a little for your tasks.
In the first part of the series, I already talked about the principles of managing Laurent modules over the network, for those who have not read the first part, I will briefly repeat the theory here.
Information is exchanged with the modules over the network and to start working with them you need to establish a TCP / IP connection on port 2424. Once the connection is established, you can send text commands (so-called KE commands) which control the module. The KernelChip website has detailed documentation, including an accessible description of KE commands.
Now let's try to translate this theoretical “terms of reference” into the plain language of Arduino's sketches.
I will not explain here how to install and configure the Arduino programming environment, it is assumed that you have already done this and are able to write simple sketches. So, for starters, we need to connect the necessary libraries SPI.h and Ethernet.h to control the bus and the Ethernet module itself.
Then you need to set the network settings for the Ethernet module and Laurent module, which we will manage. Note that MAC addresses and IP addresses must be unique, and LAURENT_PORT must be set to 2424 and no other.
We still need a buffer for storing network commands, it is selected with a size of 200 bytes with some margin, if you have problems with a lack of RAM, then you can reduce it, for example, to 100 bytes or even less.
And the final touch is the Ethernet client for the Laurent module. Now we will carry out all operations with the module using the lclient object.
That's it, now let's look at a function that sends commands to the Laurent module.
If a connection is established with the Laurent module on port 2424, the contents of the buffer are sent to the module and duplicated in Serial for visual inspection. Then 100 milliseconds are expected and the module response is received. After this, a pause again and communication with the module is broken. If for some reason the connection to the module could not be established, an error message is displayed.
Now let's analyze the initialization. Ethernet initialization is a simple function
And the Laurent module is initialized by the laurentInit () function, the operation of which we will now analyze in detail. It is quite large and you need to understand it well because it is on the basis of the code of this function that you can build your own requests to Laurent modules.
Initially, an initialization message is displayed and an attempt is made to connect to the Laurent module. If this fails, an error message is displayed, and if the connection to the module is successful, a self-diagnosis command is sent, to which the healthy module should respond with “#OK”.
Next, a command is sent to enter the password (in this case, this is the default password). And 500 milliseconds is expected.
Next, two additional commands are entered - one of them stops the data output by the module (if it goes), and the second turns off relay No. 2, which we use in our experiments. In other words, these commands bring the module to some initial state.
Here is a printout of the initialization process on which all commands and all module responses are visible:
Now the code for the standard setup () function. All subsystems are initialized, including a serial port at a standard 9600 baud rate.
So, we initialized the module and can manage it in the way we need: send commands, read answers, build control logic taking into account the data issued by the Laurent module.
Consider, for example, the simplest task - to turn on and off at regular intervals the light of a lamp connected to the second relay of the Laurent module.
The loop () function is an endless cycle and the lamp, obeying our commands, will continuously light up and go out every 3 seconds. This, of course, is just an example, in fact, the logic of work can be any and everything depends on your needs. And of course, you can send not only commands to enable or disable loads, but also any others supported by the module. You can find the complete list of commands and their description in the documentation for Laurent modules.
You can take this sketch and integrate it into your own projects, thus adding support for managing Laurent modules to them. Or vice versa, take this sketch as a basis and gradually increase its functionality. There is no limit to perfection. Here is the full sketch.
Arduino Mega Server (AMS) is a powerful system for Arduino Mega (now also for Arduino DUE and, soon, for other 32-bit platforms M0 (Zero) and Genuino 101), which contains the code “for all occasions” and plus built-in server and user-friendly web interface. AMS supports Laurent modules right out of the box and you do not need to add anything other than user logic.
AMS has a modular structure and switching modules on and off is done by simply commenting out a line in a sketch, for example,
or
If the line is commented out, then the module does not compile and does not participate in the work, as can be seen on the indicators of the modules in the header of the site. Or vice versa, a compiled and working module is indicated in blue. In this case, the LRT control module LRT does not work.
Module Operation Indicators
Now let's add the ability to not only show module responses, but also work with them, for example, analyze them or display them on Arduino Mega Server web pages. To do this, we need a new string variable and a constant that determines the length of the string that we assign to the answers of Laurent modules. In the test example, it is equal to 25 characters, but you can increase it if the answers do not fit into this value. You only need to remember that the microcontroller's RAM is a valuable resource and you need to save it. Add the following lines to the standard laurent.ino module from the AMS package:
We also need to change the code of the function that makes the requests (the added changes are highlighted by arrows).
Thus, we learned how to get Laurent answers in the lrequest variable and now we can do whatever we see fit with it. Next, I will show how to display the results of queries directly in the dash panel in the header of the AMS site.
A small note. This example uses the Serialprint function instead of the standard Serial.print because it saves more RAM. And it can be easily transformed into a standard one, simply by putting an end to two words.
And the last example. Let's display the answers of the Laurent modules in the header of the Arduino Mega Server site. To do this, we need to add the request to the main loop () loop of the AMS sketch. Open the arduino_mega_server.ino file and enter the following code before the cyclosInSecWork () function:
This code will request the health status of the Laurent module every thirty seconds. Naturally, this is just an example, at this place there can be any request and any code. Thus, in the variable lrequest we have an answer about the state of the module and can now display it in the header of the site. To do this, open the server_ajax.ino module and at the very end, in the responseDash function code (EthernetClient cl), before the line cl.println (""); add the following code:
This code, in fact, sends the module answers to the web page. It remains to do two things: the first is to add code in the JavaScript language that will “catch” our data and the second is the HTML code on the AMS page itself, where the module answers will be displayed.
So, open the scripts.js file and in the getDashData () function before the closing bracket} // if (this.responseXML! = Null) enter the code that will accept our premises.
It remains only to slightly correct the dash.htm file from the standard AMS delivery and add code to it that will display information on the screen. Immediately after the line containing class = "online-device" we enter our new line with the code:
That's all. We have displayed Laurent module responses in the header of the Arduino Mega Server site. And here is the result of our efforts. The status of the module is clearly visible in the AMS panel and it is updated every 30 seconds, so if something happens to the module, you will know about it after a maximum of 30 seconds.
As you can see, there is nothing complicated in managing Laurent modules using Arduino and Arduino Mega Server, and if you already have such modules or are planning to add them to your Smart Home system, this article will help you to do this easily and simply.
And in the next article from the series, you will learn how to manage Loranes directly from the screen of your computer and how to make the process of teaching children programming interactive and more interesting.
Addition . A Youtube channel is open and here is a promo video of the Arduino Mega Server, which demonstrates how to work with a real system.
Arduino is our everything
Where without Arduino? I’m not going to describe the advantages of this platform for a long time, its popularity speaks for itself, so let's immediately get down to the technical details of the interaction between Arduino and Laurent modules. And along the way, we will not forget the Arduino Mega Server system , as a very interesting derivative of the Arduino ecosystem.
Iron
For controlling modules over the network, for example, the common Arduino Uno board or the equally popular Arduino Mega board complete with an Ethernet Shield network interface card assembled on the basis of the W5100 chip are suitable. All examples in this article are given for such a combination and have been tested in practice. Everything works reliably and without any problems.
Ethernet Shield based on the W5100 chip
That is, you just have to take the sketch and upload it to your Uno or Mega board, after changing it a little for your tasks.
Manage Sketch Modules
In the first part of the series, I already talked about the principles of managing Laurent modules over the network, for those who have not read the first part, I will briefly repeat the theory here.
Information is exchanged with the modules over the network and to start working with them you need to establish a TCP / IP connection on port 2424. Once the connection is established, you can send text commands (so-called KE commands) which control the module. The KernelChip website has detailed documentation, including an accessible description of KE commands.
Now let's try to translate this theoretical “terms of reference” into the plain language of Arduino's sketches.
Sketch
I will not explain here how to install and configure the Arduino programming environment, it is assumed that you have already done this and are able to write simple sketches. So, for starters, we need to connect the necessary libraries SPI.h and Ethernet.h to control the bus and the Ethernet module itself.
#include
#include
Then you need to set the network settings for the Ethernet module and Laurent module, which we will manage. Note that MAC addresses and IP addresses must be unique, and LAURENT_PORT must be set to 2424 and no other.
byte SELF_MAC[] = {0x00, 0x2A, 0xF5, 0x12, 0x67, 0xEE};
byte SELF_IP[] = {192, 168, 2, 20};
byte LAURENT_IP[] = {192, 168, 2, 19};
int LAURENT_PORT = 2424;
We still need a buffer for storing network commands, it is selected with a size of 200 bytes with some margin, if you have problems with a lack of RAM, then you can reduce it, for example, to 100 bytes or even less.
char buf[200];
And the final touch is the Ethernet client for the Laurent module. Now we will carry out all operations with the module using the lclient object.
EthernetClient lclient;
That's it, now let's look at a function that sends commands to the Laurent module.
void sendLaurentRequest() {
if (lclient.connect(LAURENT_IP, LAURENT_PORT)) {
Serial.print("Command: ");
Serial.println(buf);
lclient.println(buf);
delay(100);
Serial.print("Answer: ");
while(lclient.available() != 0) {
char c = lclient.read();
Serial.print(c);
}
delay(500);
lclient.stop();
} else {
Serial.println("Error sending command");
}
}
If a connection is established with the Laurent module on port 2424, the contents of the buffer are sent to the module and duplicated in Serial for visual inspection. Then 100 milliseconds are expected and the module response is received. After this, a pause again and communication with the module is broken. If for some reason the connection to the module could not be established, an error message is displayed.
Now let's analyze the initialization. Ethernet initialization is a simple function
void ethernetInit() {
Ethernet.begin(SELF_MAC, SELF_IP);
}
And the Laurent module is initialized by the laurentInit () function, the operation of which we will now analyze in detail. It is quite large and you need to understand it well because it is on the basis of the code of this function that you can build your own requests to Laurent modules.
void laurentInit() {
Serial.println("Start modul Laurent Init...");
Serial.print("Connect to Laurent... ");
if (lclient.connect(LAURENT_IP, LAURENT_PORT)) {
Serial.println("OK");
lclient.stop();
// Send test command
Serial.println("Selftest...");
sprintf(buf, "$KE");
sendLaurentRequest();
// Send password (default: "Laurent")
Serial.println("Set password...");
sprintf(buf, "$KE,PSW,SET,Laurent");
sendLaurentRequest();
} else {
Serial.println("failed");
}
delay(500);
// останавливаем выдачу DATA
sprintf(buf, "$KE,DAT,OFF");
sendLaurentRequest();
delay(100);
// выключаем реле
sprintf(buf, "$KE,REL,2,0");
sendLaurentRequest();
Serial.println("Modul Laurent Init done");
}
Initially, an initialization message is displayed and an attempt is made to connect to the Laurent module. If this fails, an error message is displayed, and if the connection to the module is successful, a self-diagnosis command is sent, to which the healthy module should respond with “#OK”.
Next, a command is sent to enter the password (in this case, this is the default password). And 500 milliseconds is expected.
Next, two additional commands are entered - one of them stops the data output by the module (if it goes), and the second turns off relay No. 2, which we use in our experiments. In other words, these commands bring the module to some initial state.
Here is a printout of the initialization process on which all commands and all module responses are visible:
Start modul Laurent Init...
Connect to Laurent... OK
Selftest...
Command: $KE
Answer: #OK
Set password...
Command: $KE,PSW,SET,Laurent
Answer: #PSW,SET,OK
Command: $KE,DAT,OFF
Answer: #DAT,OK
Command: $KE,REL,2,0
Answer: #REL,OK
Modul Laurent Init done
Now the code for the standard setup () function. All subsystems are initialized, including a serial port at a standard 9600 baud rate.
void setup() {
Serial.begin(9600);
ethernetInit();
laurentInit();
}
So, we initialized the module and can manage it in the way we need: send commands, read answers, build control logic taking into account the data issued by the Laurent module.
Consider, for example, the simplest task - to turn on and off at regular intervals the light of a lamp connected to the second relay of the Laurent module.
void loop() {
// включаем реле
sprintf(buf, "$KE,REL,2,1");
sendLaurentRequest();
delay(3000);
// выключаем реле
sprintf(buf, "$KE,REL,2,0");
sendLaurentRequest();
delay(3000);
}
The loop () function is an endless cycle and the lamp, obeying our commands, will continuously light up and go out every 3 seconds. This, of course, is just an example, in fact, the logic of work can be any and everything depends on your needs. And of course, you can send not only commands to enable or disable loads, but also any others supported by the module. You can find the complete list of commands and their description in the documentation for Laurent modules.
You can take this sketch and integrate it into your own projects, thus adding support for managing Laurent modules to them. Or vice versa, take this sketch as a basis and gradually increase its functionality. There is no limit to perfection. Here is the full sketch.
Full sketch code
#include
#include
byte SELF_MAC [] = {0x00, 0x2A, 0xF5, 0x12, 0x67, 0xEE};
byte SELF_IP [] = {192, 168, 2, 20};
byte LAURENT_IP [] = {192, 168, 2, 19};
int LAURENT_PORT = 2424;
char buf [200];
EthernetClient lclient;
void ethernetInit () {
Ethernet.begin (SELF_MAC, SELF_IP);
}
void laurentInit () {
Serial.println ("Start modul Laurent Init ...");
Serial.print (“Connect to Laurent ...„);
if (lclient.connect (LAURENT_IP, LAURENT_PORT)) {
Serial.println (“OK”);
lclient.stop ();
// Send test command
Serial.println ("Selftest ...");
sprintf (buf, "$ KE");
sendLaurentRequest ();
// Send password (default: "Laurent")
Serial.println ("Set password ...");
sprintf (buf, "$ KE, PSW, SET, Laurent");
sendLaurentRequest ();
} else {
Serial.println ("failed");
}
delay (500);
// stop issuing DATA
sprintf (buf, "$ KE, DAT, OFF");
sendLaurentRequest ();
delay (100);
// turn off the relay
sprintf (buf, "$ KE, REL, 2.0");
sendLaurentRequest ();
Serial.println ("Modul Laurent Init done");
} // laurentInit
void sendLaurentRequest () {
if (lclient.connect (LAURENT_IP, LAURENT_PORT)) {
Serial.print ("Command:„);
Serial.println (buf);
lclient.println (buf);
delay (100);
Serial.print (“Answer:„);
while (lclient.available ()! = 0) {
char c = lclient.read ();
Serial.print ©;
}
delay (500);
lclient.stop ();
} else {
Serial.println (“Error sending command”);
}
} // sendLaurentRequest
void setup () {
Serial.begin (9600);
ethernetInit ();
laurentInit ();
}
void loop () {
// enable the relay
sprintf (buf, "$ KE, REL, 2.1");
sendLaurentRequest ();
delay (3000);
// turn off the relay
sprintf (buf, "$ KE, REL, 2.0");
sendLaurentRequest ();
delay (3000);
}
#include
byte SELF_MAC [] = {0x00, 0x2A, 0xF5, 0x12, 0x67, 0xEE};
byte SELF_IP [] = {192, 168, 2, 20};
byte LAURENT_IP [] = {192, 168, 2, 19};
int LAURENT_PORT = 2424;
char buf [200];
EthernetClient lclient;
void ethernetInit () {
Ethernet.begin (SELF_MAC, SELF_IP);
}
void laurentInit () {
Serial.println ("Start modul Laurent Init ...");
Serial.print (“Connect to Laurent ...„);
if (lclient.connect (LAURENT_IP, LAURENT_PORT)) {
Serial.println (“OK”);
lclient.stop ();
// Send test command
Serial.println ("Selftest ...");
sprintf (buf, "$ KE");
sendLaurentRequest ();
// Send password (default: "Laurent")
Serial.println ("Set password ...");
sprintf (buf, "$ KE, PSW, SET, Laurent");
sendLaurentRequest ();
} else {
Serial.println ("failed");
}
delay (500);
// stop issuing DATA
sprintf (buf, "$ KE, DAT, OFF");
sendLaurentRequest ();
delay (100);
// turn off the relay
sprintf (buf, "$ KE, REL, 2.0");
sendLaurentRequest ();
Serial.println ("Modul Laurent Init done");
} // laurentInit
void sendLaurentRequest () {
if (lclient.connect (LAURENT_IP, LAURENT_PORT)) {
Serial.print ("Command:„);
Serial.println (buf);
lclient.println (buf);
delay (100);
Serial.print (“Answer:„);
while (lclient.available ()! = 0) {
char c = lclient.read ();
Serial.print ©;
}
delay (500);
lclient.stop ();
} else {
Serial.println (“Error sending command”);
}
} // sendLaurentRequest
void setup () {
Serial.begin (9600);
ethernetInit ();
laurentInit ();
}
void loop () {
// enable the relay
sprintf (buf, "$ KE, REL, 2.1");
sendLaurentRequest ();
delay (3000);
// turn off the relay
sprintf (buf, "$ KE, REL, 2.0");
sendLaurentRequest ();
delay (3000);
}
Arduino Mega Server
Arduino Mega Server (AMS) is a powerful system for Arduino Mega (now also for Arduino DUE and, soon, for other 32-bit platforms M0 (Zero) and Genuino 101), which contains the code “for all occasions” and plus built-in server and user-friendly web interface. AMS supports Laurent modules right out of the box and you do not need to add anything other than user logic.
AMS has a modular structure and switching modules on and off is done by simply commenting out a line in a sketch, for example,
#define LAURENT_FEATURE
or
//#define LAURENT_FEATURE
If the line is commented out, then the module does not compile and does not participate in the work, as can be seen on the indicators of the modules in the header of the site. Or vice versa, a compiled and working module is indicated in blue. In this case, the LRT control module LRT does not work.
Module Operation Indicators
Working with Laurent module responses
Now let's add the ability to not only show module responses, but also work with them, for example, analyze them or display them on Arduino Mega Server web pages. To do this, we need a new string variable and a constant that determines the length of the string that we assign to the answers of Laurent modules. In the test example, it is equal to 25 characters, but you can increase it if the answers do not fit into this value. You only need to remember that the microcontroller's RAM is a valuable resource and you need to save it. Add the following lines to the standard laurent.ino module from the AMS package:
byte MAX_LEN_LREQUEST = 25;
String lrequest = String(MAX_LEN_LREQUEST);
We also need to change the code of the function that makes the requests (the added changes are highlighted by arrows).
void sendLaurentRequest() {
if (lclient.connect(LAURENT_IP, LAURENT_PORT)) {
Serialprint("Command: ");
Serial.println(buf);
lclient.println(buf);
delay(100);
Serialprint("Answer: ");
// -------------------->
lrequest = "";
// -------------------->
while(lclient.available() != 0) {
char c = lclient.read();
Serial.print(c);
// -------------------->
if (lrequest.length() < MAX_LEN_LREQUEST) {
lrequest += (c);
}
// -------------------->
}
delay(500);
lclient.stop();
} else {
Serialprint("Error sending command\n");
}
}
Thus, we learned how to get Laurent answers in the lrequest variable and now we can do whatever we see fit with it. Next, I will show how to display the results of queries directly in the dash panel in the header of the AMS site.
A small note. This example uses the Serialprint function instead of the standard Serial.print because it saves more RAM. And it can be easily transformed into a standard one, simply by putting an end to two words.
Outputting the module response to the site header
And the last example. Let's display the answers of the Laurent modules in the header of the Arduino Mega Server site. To do this, we need to add the request to the main loop () loop of the AMS sketch. Open the arduino_mega_server.ino file and enter the following code before the cyclosInSecWork () function:
#ifdef LAURENT_FEATURE
if (cycle30s) {
sprintf(buf, "$KE");
sendLaurentRequest();
}
#endif
This code will request the health status of the Laurent module every thirty seconds. Naturally, this is just an example, at this place there can be any request and any code. Thus, in the variable lrequest we have an answer about the state of the module and can now display it in the header of the site. To do this, open the server_ajax.ino module and at the very end, in the responseDash function code (EthernetClient cl), before the line cl.println (""); add the following code:
#ifdef LAURENT_FEATURE
sendTagString("laurent", "", lrequest, cl);
#endif
This code, in fact, sends the module answers to the web page. It remains to do two things: the first is to add code in the JavaScript language that will “catch” our data and the second is the HTML code on the AMS page itself, where the module answers will be displayed.
So, open the scripts.js file and in the getDashData () function before the closing bracket} // if (this.responseXML! = Null) enter the code that will accept our premises.
// Laurent
try {
var laurent = this.responseXML.getElementsByTagName('laurent')[0].childNodes[0].nodeValue;
} catch (err) {
laurent = "-";
}
document.getElementById("laurent").innerHTML = laurent;
It remains only to slightly correct the dash.htm file from the standard AMS delivery and add code to it that will display information on the screen. Immediately after the line containing class = "online-device" we enter our new line with the code:
Laurent: ...
That's all. We have displayed Laurent module responses in the header of the Arduino Mega Server site. And here is the result of our efforts. The status of the module is clearly visible in the AMS panel and it is updated every 30 seconds, so if something happens to the module, you will know about it after a maximum of 30 seconds.
Conclusion
As you can see, there is nothing complicated in managing Laurent modules using Arduino and Arduino Mega Server, and if you already have such modules or are planning to add them to your Smart Home system, this article will help you to do this easily and simply.
And in the next article from the series, you will learn how to manage Loranes directly from the screen of your computer and how to make the process of teaching children programming interactive and more interesting.
Addition . A Youtube channel is open and here is a promo video of the Arduino Mega Server, which demonstrates how to work with a real system.