📜 ⬆️ ⬇️

Intel Edison in IoT: securely connecting the touch node to the Internet using MQTT

We already wrote about the MQTT broker and how to assemble a touch node based on Intel Edison . The device contains a button, motion sensors, temperature and light. Today we will connect all this to the Mosquitto MQTT-server, we will establish two-way communication, we will make our design a full-fledged part of the Internet of things.



MQTT


Model publisher-subscriber in MQTT


MQTT is one of the popular protocols for the organization of machine-to-machine communication (M2M, Machine to Machine). It works on the “publisher-subscriber” principle and is based on TCP / IP. The two main components of the MQTT are the client and the broker. MQTT-clients publish messages on a specific topic (topic), or subscribe to messages and listen to them. The MQTT broker receives all messages published by publishers and forwards relevant messages to subscribers. Subscribers and publishers should not know about each other, only the topics of the messages and the messages themselves play a role. For the organization of normal interaction publishers and subscribers should use the common names of topics and message format.

To post messages, or subscribe to messages of a particular topic, you need an MQTT client. In the Mosquitto MQTT distribution, the client publishing messages is called mosquitto_pub, and the client subscribing to messages is called mosquitto_sub.
This is what messaging looks like, which we'll talk about below. The red window shows the work of the client-subscriber, in black - the client-publisher. Commands are tagged, it will allow you to refer to them conveniently.
')

Subscriber / Publisher Interaction

The minimum set of arguments required for subscribers-subscribers is the broker's IP address and the name of the message subject, and for the publisher customers, the message text. Provided that the MQTT broker is available at 127.0.0.1 (localhost), the command shown below will listen to all messages published with the theme “edison / hello”.

sub 3> mosquitto_sub –h localhost –t edison/hello 

But how can you post a message with the theme "edison / hello".

 pub 3> mosquitto_pub –h localhost –t edison/hello –m "Message#1: Hello World!" 

When the MQTT broker receives a message “Message # 1: Hello World” from the publishing client (pub 3), published with the topic “edison / hello”, the broker looks at the list of customers who are subscribed to the topic “edison / hello”. Upon finding that the subscriber client (sub 3) is subscribed to the specified topic, the MQTT broker forwards the message to this client.

When a subscriber receives a message, he displays it in a terminal window. In the commands of the subscriber sub 3 and publisher pub 3, the MQTT port number is implicitly given by default (1833), so it is not specified on the command line. In the sub 4 and pub 4 commands the port number is specified. In the sub 5 and pub 5 commands, the key “-v” has been added to the arguments to the subscription. This allows you to display in the terminal window not only the message, but also the name of the topic. This will be useful when subscribing to several topics using templates. A subscriber once created is not automatically destroyed, so additional messages published with the theme “edison / hello”, for example, using the pub 6 command, will be redirected to this subscriber.

The standard behavior of the MQTT broker is that it discards the message immediately after it is delivered to the clients. The pub 7 client publishes a message with a new theme, “edison / hello1”, but the subscriber client sub 5 is waiting for messages with the theme “edison / hello”, so he will not receive messages from pub 7. Then the subscriber client, sub 6, subscribes to the edison / hello1 topic, but he also will not receive a previously sent message with this topic, since it has already been dropped. He will receive only the following messages published with this topic, for example, published in the pub 8 line.

There are additional parameters that instruct the MQTT broker to save the last message published with a certain topic. There are directives that allow you to customize the quality of service (Quality of Service, QoS), which affect how the broker will deliver messages. Details on these features can be found in the MQTT Wiki .
Depending on the port configuration, additional arguments may be needed. We will return to this question later.

Subscribe to several topics


Usually in practice, MQTT clients are used, which are subscribed to several topics and perform different actions depending on the messages received. Let's talk about MQTT topics.

MQTT topics are organized in a hierarchical structure. The symbol "/" is used to highlight the logical levels of topics. This is what a logically constructed topic space might look like.

 Temperature/Building1/Room1/Location1 Temperature/Building1/Room1/Location2 Temperature/Building2/Room2 Temperature/Outdoor/West Temperature/Outdoor/East Temperature/Average 

A subscriber can subscribe to a specific topic, say, “Temperature / Outdoor / West”, or several using a template.

There are two wildcard characters in MQTT: “+” and “#”. The “+” symbol is used to subscribe to topics that are at the same hierarchy level. The “#” symbol is used to subscribe to all subsections of a given topic.

For example, a subscription to the topic “Temperature / #” will deliver a message to the client with any of the topics shown in the example. By subscribing to Temperature / +, the client will receive only messages with the subject Temperature / Average, since all other topics are at a lower hierarchical level. Details on the organization of MQTT theme spaces can be found on the MQTT Wiki site .

Setting up a safe broker Mosquitto


The MQTT client can be connected to the Mosquitto server in four main ways.

  1. Through the open port, that is, without protection. This is useful when developing and testing MQTT devices before practical use. Data between the broker and the client are transmitted in plain text, without encryption. As a result, they are easy to intercept.

  2. Using a username and password. With this method, the broker can verify the authenticity of the client. However, data is not encrypted during transmission.

  3. Using TLS-PSK encryption. The client and the broker have a shared secret key, which is used when establishing a secure connection. This feature is available starting from Mosquitto 1.3.5.

  4. Using SSL encryption. This is the most advanced encryption and authentication scheme available in the Mosquitto MQTT. When using SSL, you must obtain a server certificate from a trusted certificate authority (Certificate Authority, CA), among such centers - Verisign and Equifax. Often, for testing, they create a self-generated certificate that can be used to sign the server certificate. SSL allows you to achieve a high level of security, but to implement such a scheme of work is more difficult than others. The fact is that when using SSL you need to provide all the client devices with the appropriate certificates. In addition, it is necessary to develop an update mechanism to maintain compliance of certificates of clients and broker during the operation of the system.

To configure the Mosquitto MQTT secure broker, use the following configuration directives. Here a self-generated certificate is used that is suitable for test purposes. Such certificates should not be used on production servers.

 port 1883 password_file /home/mosquitto/conf/pwdfile.txt log_type debug log_type error log_type warning log_type information log_type notice user root pid_file /home/mosquitto/logs/mosquitto.pid persistence true persistence_location /home/mosquitto/db/ log_dest file /home/mosquitto/logs/mosquitto.log listener 1995 #  1995    TLS-PSK,     #  --psk-identity  --psk psk_file /home/mosquitto/conf/pskfile.txt #   psk_hint,   1995     psk_hint hint listener 1994 #  1994   SSL-,     #  ,   , #   , , ca.crt cafile /home/mosquitto/certs/ca.crt certfile /home/mosquitto/certs/server.crt keyfile /home/mosquitto/certs/server.key 

The pwdfile.txt file in this example is a password file, encrypted in the same way as the Linux password file. It can be created using the mosquitto_passwd utility that comes with Mosquitto. The pskfile.txt file is a password file that is pre-hosted on clients and on the server. It is used to establish a connection using TLS-PSK. This is a plain text file, each line of which contains one pair of “user: password” type. Passwords that are used for TLS-PSK are not case sensitive and can contain only hexadecimal characters. Here are some examples of the password file and the .psk file.

 /*    Mosquitto */ user:$6$Su4WZkkQ0LmqeD/X$Q57AYfcu27McE14/MojWgto7fmloRyrZ7BpTtKOkME8UZzJZ5hGXpOea81RlgcXttJbeRFY9s0f+UTY2dO5xdg== /*  PSK- Mosquitto */ user1:deadbeef user2:DEADBEEF0123456789ABCDEF0123456789abcdef0123456789abcdef0123456789abcdef <h1> MQTT   </h1> 

Since Intel Edison is a Linux system that can run a program (sketch) for Arduino as one of its processes, you can use the Mosquitto MQTT package that we have already prepared. Linux programming tools are available within the sketch to call mosquitto_sub and mosquitto_pub . There are several advantages to this approach.

  1. No need to rewrite MQTT clients for Arduino. The Mosquitto MQTT package is a well-known and well-tested code. We only need to create a wrapper class in order to be able to use it in the Arduino-sketch.

  2. Mosquitto MQTT clients support secure SSL connections. At the same time, a low-power microcontroller in a regular Arduino does not meet the computational requirements of SSL.

  3. If a more advanced MQTT packet is found or a new version of what is already in use is released, most of the existing code can be reused, adding new support for it.

MQTTClient class


Since Intel Edison is running a full-featured Linux OS, the Arduino program is available for all Linux development tools. Create a wrapper class, MQTTClient, which will be used in the sketch. In the MQTTClietn methods, we use Linux system calls to call mosquitto_sub and mosquitto_pub , which, in turn, will deal with communication tasks using the MQTT protocol. Here is the MQTTClent class description, limited by the minimum required features.

 // : MQTTClient.h /*  MQTT-,  mosquitto_sub  mosquitto_pub   ,   Mosquitto MQTT   mosquitto_pub/sub      */ #ifndef __MQTTClient_H__ #define __MQTTClient_H__ #include <Arduino.h> #include <stdio.h> enum security_mode {OPEN = 0, SSL = 1, PSK = 2}; class MQTTClient { public:   MQTTClient();   ~MQTTClient();   void    begin(char * broker, int port, security_mode mode,                 char* certificate_file, char *psk_identity, char *psk);   boolean publish(char *topic, char *message);   boolean subscribe(char* topic, void (*callback)(char *topic, char* message));   boolean loop();   boolean available();   void    close(); private:   void           parseDataBuffer();   FILE*          spipe;   char           mqtt_broker[32];   security_mode  mode;   char           topicString[64];   char           certificate_file[64];   char           psk_identity[32];   char           psk_password[32];   int            serverPort;   char           *topic;   char           *message;   boolean         retain_flag;   void           (*callback_function)(char* topic, char* message);   char           dataBuffer[256]; }; #endif 

To use this class, you need to start by creating an MQTTClient object, then call MQTTClient :: begin () to initialize the various variables that will use MQTTClient :: subscribe () and MQTTClient :: publish () to connect to the MQTT broker . Here is a description of these variables.


In order to subscribe to a topic, call the MQTTClient: subscribe () method with the name of the topic and the callback function that will be launched when a new message arrives. To post a message with a topic, call MQTTClient: publish () with the name of the topic and the message.

Both in the message subscription method and in the publication method, the corresponding command is formed, which calls either mosquitto_sub or mosquitto_pub and uses argument methods and saved parameters. Then the Linux channel opens, the command is executed, the results are returned via the channel to the sketch.

When publishing, the channel closes immediately after the message is sent. When you subscribe, the channel must be kept open so that new data can be obtained through it. The MQTTClient: loop () method was created to periodically check for data in the channel and call callback functions to process new messages. Since the Linux channel will be blocked, if nothing happens, we made the channels non-blocking. Thus, if when checking in the MQTTClient: loop () method that the channel is empty, an immediate return from the method will occur. The pseudo-code below shows a typical use of the MQTTClient class.

 #include <MQTTClient.h> #define SAMPLING_PERIOD   100 #define PUBLISH_INTERVAL  30000 MQTTClient mqttClient; void setup() {  mqttClient.begin("localhost",1833,PSK,NULL,"psk_user","psk_password");  mqttClient.subscribe("edison/#",myCallBack); } void myCallBack(char* topic, char* message) {  //    , ,   } unsigned long publishTime = millis(); void loop() {  mqttClient.loop();        //       if (millis() > publishTime) {      publishTime = millis() + PUBLISH_INTERVAL;      mqttClient.publish("edison/sensor1","sensor1value");      mqttClient.publish("edison/sensor2","sensor2value");  }  delay(SAMPLING_PERIOD); } 

The variable " SAMPLING_PERIOD " sets the frequency with which new messages will be checked. The value of this variable should be chosen so that the messages that should trigger any actions by the Arduino program arrive not too late and do not lose their meaning.

Most of the working time, the MQTTClietn: loop () method will end very quickly, so frequently invoking this method will create a very small load on the system. The interval with which messages are published is set using the variable “ PUBLISH_INTERVAL ”. The duration of the interval should correspond to the frequency with which the sensors publish data. For example, a temperature sensor may publish room temperature information once a minute, if its indicators are used for informational purposes. But the smoke detector makes sense to publish data every few seconds so that the subscriber, who is waiting for his messages, in the event of the sensor triggered, has a chance to do something before it is too late.

Here is the implementation of the MQTTClient class.

 // : MQTTClient.cpp #include "MQTTClient.h" #include <fcntl.h> /*====================================================================== / ========================================================================*/ MQTTClient::MQTTClient() { } MQTTClient::~MQTTClient() { close(); } void MQTTClient::close() { if (spipe) {   fclose(spipe); } } /*======================================================================== .             ==========================================================================*/ void MQTTClient::begin(char *broker, int port, security_mode smode,                      char* cafile, char *user, char *psk) { strcpy(mqtt_broker, broker); serverPort = port; mode = smode; if (mode == SSL) {   strcpy(certificate_file, cafile); } else if (mode == PSK) {   strcpy(psk_identity, user);   strcpy(psk_password, psk); } Serial.println("MQTTClient initialized"); Serial.print("Broker: "); Serial.println(mqtt_broker); Serial.print("Port:   "); Serial.println(serverPort); Serial.print("Mode:   "); Serial.println(mode); } /*=======================================================================   , (*callback)  ,   ,    . =========================================================================*/ boolean MQTTClient::subscribe(char* topic,                             void (*callback)(char* topic, char* message)) { char cmdString[256]; if (mqtt_broker == NULL) {   return false; } if (topic == NULL) {   return false; } callback_function = callback; switch(mode) {   case OPEN:     sprintf(cmdString,             "mosquitto_sub -h %s -p %d -t %s -v",             mqtt_broker, serverPort, topic);     break;   case SSL:     sprintf(cmdString,             "mosquitto_sub -h %s -p %d -t %s -v --cafile %s",              mqtt_broker, serverPort, topic, certificate_file);     break;   case PSK:     sprintf(cmdString,             "mosquitto_sub -h %s -p %d -t %s -v --psk-identity %s --psk %s",             mqtt_broker, serverPort, topic, psk_identity, psk_password);     break;   default:     break; } if ((spipe = (FILE*)popen(cmdString, "r")) != NULL) {   //         int fd    = fileno(spipe);   int flags = fcntl(fd, F_GETFL, 0);   flags |= O_NONBLOCK;   fcntl(fd, F_SETFL, flags);   strcpy(topicString, topic);   return true; } else {   return false; } } /*==================================================================== ,     ,  ,         .  ,   . ======================================================================*/ boolean MQTTClient::loop() { if (fgets(dataBuffer, sizeof(dataBuffer), spipe)) {      parseDataBuffer();      callback_function(topic, message); } } /*====================================================================     . ======================================================================*/ boolean MQTTClient::publish(char *topic, char *message) { FILE*   ppipe; char    cmdString[256]; boolean retval = false; if (this->mqtt_broker == NULL) {   return false; } if (topic == NULL) {   return false; } switch (this->mode) {   case OPEN:     sprintf(cmdString,             "mosquitto_pub -h %s -p %d -t %s -m \"%s\" %s",             mqtt_broker, serverPort, topic, message, retain_flag?"-r":"");     break;   case SSL:     sprintf(cmdString,             "mosquitto_pub -h %s -p %d --cafile %s -t %s -m \"%s\" %s",              mqtt_broker, serverPort, certificate_file,              topic, message, retain_flag?"-r":"");     break;   case PSK:     sprintf(cmdString,         "mosquitto_pub -h %s -p %d --psk-identity %s --psk %s -t %s -m \"%s\" %s",             mqtt_broker, serverPort, psk_identity, psk_password,             topic, message, retain_flag?"-r":"");     break; } if (!(ppipe = (FILE *)popen(cmdString, "w"))) {   retval = false; } if (fputs(cmdString, ppipe) != EOF) {   retval = true; } else {   retval = false; } fclose(ppipe); return retval; } /*======================================================================    ,        .    .         , ,         NULL ========================================================================*/ void MQTTClient::parseDataBuffer() { topic   = dataBuffer; message = dataBuffer; while((*message) != 0) {   if ((*message) == 0x20) {     //     NULL     (*message) = 0;     message++;     break;   }   else {     message++;   } } if (strlen(message) == 0) {   topic   = NULL;   message = dataBuffer; } } <h2> </h2> 

In one of the previous publications we talked about the assembly of a sensor node with sensors and actuators. Namely, this is what the device consists of, which then turned out to be created:

  1. Motion sensor for motion detection.
  2. Temperature sensor that allows you to measure the ambient temperature.
  3. Light sensor that measures light.
  4. Command button that allows you to recognize targeted user actions. In this case - pressing the button.
  5. Red LED that turns on and off in response to button presses.
  6. Green LED that turns on when a motion sensor is triggered.


Intel Edison Touch Node

Using MQTT, we will periodically publish indicators of various sensors, transmitting messages to the Mosquitto broker, which runs on the same Intel Edison system. Subscribe to all topics, that is, to "edison / #". In addition, we will make some changes in the logic of the sensor node:

  1. The command button will no longer turn on and off the red LED. Now clicking on it will serve as a signal to change the value of the logical variable that will be transmitted to the subscribers of MQTT.

  2. The red LED will turn on and off using MQTT messages. Such a mechanism can play the role of an access module for a lighting device that can be controlled via the Internet.

  3. The behavior of the green LED can be configured using MQTT. Namely, it will be possible to make it turn on when the motion sensor is triggered, or stay off all the time.

Here is the main sketch code.

 // : MQTT_IoT_Sensor.ino /******************************************************************************       ,    Intel Edison ******************************************************************************/ #include <stdio.h> #include <Arduino.h> #include "sensors.h" #include "MQTTClient.h" //   unsigned long          updateTime = 0; //    volatile unsigned long activityMeasure; volatile unsigned long activityStart; volatile boolean       motionLED = true; unsigned long          resetActivityCounterTime; //   boolean                toggleLED = false; volatile unsigned long previousEdgeTime = 0; volatile unsigned long count = 0; volatile boolean       arm_alarm = false; // MQTT- #define SECURE_MODE     2 MQTTClient              mqttClient; char                    fmtString[256];     //   char                    topicString[64];    //    char                    msgString[64];      //  /*****************************************************************************  ******************************************************************************/ void setup() { Serial.begin(115200); delay(3000); Serial.println("Ready"); pinMode(RED_LED,    OUTPUT); pinMode(GREEN_LED,  OUTPUT); pinMode(BUTTON,     INPUT_PULLUP); pinMode(PIR_SENSOR, INPUT); //  .      attachInterrupt(BUTTON,     buttonISR, RISING);  //   .        attachInterrupt(PIR_SENSOR, pirISR,    CHANGE); digitalWrite(RED_LED,  HIGH); digitalWrite(GREEN_LED,LOW); resetActivityCounterTime = 0; //  MQTTClient #if ( SECURE_MODE == 0 ) Serial.println("No security"); mqttClient.begin("localhost", 1883, OPEN, NULL, NULL, NULL); #elif ( SECURE_MODE == 1 ) Serial.println("SSL security"); mqttClient.begin("localhost", 1994, SSL,                  "/home/mosquitto/certs/ca.crt", NULL, NULL); #elif ( SECURE_MODE == 2 ) Serial.println("TLS-PSK security"); mqttClient.begin("localhost", 1995, PSK, NULL, "user", "deadbeef"); #endif //      edison mqttClient.subscribe("edison/#", mqttCallback); mqttClient.publish("edison/bootMsg","Booted"); digitalWrite(RED_LED, LOW); } /**************************************************************************    MQTT **************************************************************************/ void mqttCallback(char* topic, char* message) { sprintf(fmtString, "mqttCallback(), topic: %s, message: %s",topic,message); Serial.print(fmtString); //   if (strcmp(topic,"edison/LED") == 0) {   //       if (message[0] == 'H') {     digitalWrite(RED_LED, HIGH);     toggleLED = false;   }   else if (message[0] == 'L') {     digitalWrite(RED_LED, LOW);     toggleLED = false;   }   else if (message[0] == 'B') {     toggleLED = true;   } } if (strcmp(topic, "edison/motionLED") == 0) {   //    ,         //   .   //  strncmp  ,       if (strncmp(message, "OFF", 3) == 0) {     digitalWrite(GREEN_LED, LOW);     motionLED = false;   }   else if (strncmp(message, "ON", 2) == 0) {     motionLED = true;   } } } /***********************************************************************   ***********************************************************************/ void loop() {   // ,      mqtt_sub   mqttClient.loop();     if (millis() > resetActivityCounterTime) {     resetActivityCounterTime = millis() + 60000;     //    ,        sprintf(msgString,"%.0f",100.0*activityMeasure/60000.0);     mqttClient.publish("edison/ActivityLevel",msgString);     activityMeasure = 0;   }   if (millis() > updateTime) {     updateTime = millis() + 10000;        //         sprintf(msgString,"%.1f",readTemperature(TEMP_SENSOR));     mqttClient.publish("edison/Temperature",msgString);         //         sprintf(msgString,"%d",readLightSensor(LIGHT_SENSOR));     mqttClient.publish("edison/LightSensor",msgString);         //  arm_alarm     sprintf(msgString,"%s", (arm_alarm == true)? "ARMED"  : "NOTARMED");     mqttClient.publish("edison/alarm_status", msgString);   }     if (toggleLED == true) {     digitalWrite(RED_LED, digitalRead(RED_LED) ^ 1);   }   delay(100); } 

. , , , , sensor.h sensor.cpp .

SECURE_MODE Arduino- . , mqttCallback(), , MQTT-. , , , . , , , .

– , IoT- . «edison/LED» , . «edison/motionLED» . , .

 // : sensors.h // #define USE_TMP036     0 #define RED_LED       10            //   #define GREEN_LED     11            //   #define BUTTON        13            //       10K #define PIR_SENSOR    12            //    #define LIGHT_SENSOR  A0            //   #define TEMP_SENSOR   A1            //   TMP36  LM35 #define MIN_PULSE_SEPARATION     200   //     #define ADC_STEPSIZE             4.61  //  ,     . #if (USE_TMP036 == 1) #define TEMP_SENSOR_OFFSET_VOLTAGE       750 #define TEMP_SENSOR_OFFSET_TEMPERATURE   25 #else // LM35 temperature sensor #define TEMP_SENSOR_OFFSET_VOLTAGE        0 #define TEMP_SENSOR_OFFSET_TEMPERATURE    0 #endif //   extern unsigned long          updateTime; //    extern volatile unsigned long activityMeasure; extern volatile unsigned long activityStart; extern volatile boolean       motionLED; extern unsigned long          resetActivityCounterTime; //   extern boolean                toggleLED; extern volatile unsigned long previousEdgeTime; extern volatile unsigned long count; extern volatile boolean       arm_alarm; float readTemperature(int analogPin); int   readLightSensor(int analogPin); void  buttonISR(); void  pirISR(); // : sensors.cpp #include <Arduino.h> #include "sensors.h" /***********************************************************************************    ,    ,     HIGH      ,   .   ,     HIGH  2-3 ,     LOW.        HIGH,       .               ************************************************************************************/ void pirISR() { int pirReading; unsigned long timestamp; timestamp = millis(); pirReading = digitalRead(PIR_SENSOR); if (pirReading == 1) {   //      activityStart = timestamp; } else {   int pulseWidth = timestamp-activityStart;   activityMeasure += pulseWidth; } //   ,    if (motionLED == true) {   digitalWrite(GREEN_LED, pirReading); } } /************************************************************************     ************************************************************************/ int readLightSensor(int sensorPin) { return analogRead(sensorPin); } /***********************************************************************        ***********************************************************************/ float readTemperature(int sensorPin) { int   sensorReading; float temperature; sensorReading = analogRead(sensorPin); //    temperature = sensorReading * ADC_STEPSIZE; //   LM35,  TMP036,   : // 10     //    LM35 – 0 ,  TMP036 - 750  //    LM35 – 0  ,  TMP036 – 25 . temperature = (temperature - TEMP_SENSOR_OFFSET_VOLTAGE)/10.0 +                TEMP_SENSOR_OFFSET_TEMPERATURE; //     temperature = temperature * 1.8 + 32.0;        return temperature; } /*************************************************************************     **************************************************************************/ void buttonISR() { //        ,    if ((millis()-previousEdgeTime) >= MIN_PULSE_SEPARATION) {   arm_alarm = !arm_alarm;   Serial.print("Alarm is: ");   if (arm_alarm == true) {     Serial.println("ARMED");   }   else {     Serial.println("NOT ARMED");   }   count++;   Serial.print("Count: "); Serial.println(count); } previousEdgeTime=millis(); } 


, , MQTT- , , – , .

Edison SSH mosquitto_sub/pub . -, Mosquitto.
, .

, , :

 $> mosquitto_sub –h ipaddr –p 1883 –t edison/# -v 

ipaddr – IP- Intel Edison. Edison, IP- «localhost». , 1883. 1994, SSL-. 1995, PSK, . «edison/#» , .

, , «edison/LED», , «edison/motionLED», .

 $> mosquitto_pub –h ipaddr –p 1883 –t Edison/LED –m {H, L, B} $> mosquitto_pub –h ipaddr –p 1883 –t Edison/motionLED –m {ON, OFF} 

(H, L, B) , .
, , , , ON OFF.

, .

findings


, , Mosquitto MQTT, Linux Intel Edison. , Arduino . Linux, , , Arduino-, , Linux.

Source: https://habr.com/ru/post/283440/


All Articles