| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| en:iot-open:remotelab:sut:roboarm:u9 [2020/05/13 09:16] – pczekalski | en:iot-open:remotelab:sut:roboarm:u9 [2020/07/20 09:00] (current) – external edit 127.0.0.1 |
|---|
| ==== U9: A CoAP client ==== | ==== U9: A CoAP client ==== |
| In this scenario, you will interact with a CoAP server implemented as a NodeRED node. You will perform simple CoAP request. | In this scenario, you will interact with a CoAP server implemented as a NodeRED node. You will perform simple CoAP request to the NodeRED server, waiting for you. In return, you will obtain a secret code. |
| |
| === Target group === | === Target group === |
| * handle LCD screen to present information (refer to the scenarios B1 and B2 when in doubt), | * handle LCD screen to present information (refer to the scenarios B1 and B2 when in doubt), |
| * connect to the existing WiFi network: ''internal.IOT'', | * connect to the existing WiFi network: ''internal.IOT'', |
| | * additionally, we will ask you to install and use a CoAP client of your choice. We suggest using chrome extension [[https://github.com/mkovatsc/Copper4Cr/blob/master/README.md|Cooper4Cr, chrome plugin]], but any CoAP client will work here. You connect your solution to the private IP of the NodeRED server but the same information is available on the public IP as well, so you can check it from your home. |
| |
| * additionally, we will ask you to install and use a CoAP client of your choice. We suggest using [[https://github.com/eclipse/paho.mqtt-spy/releases|MQTT Spy]], but any MQTT client that will let you subscribe to the MQTT messages is OK. You connect it to the public IP of the MQTT broker (see below). | NodeRED CoAP server is present in the ''internal.IOT'' network and it is also visible under public address. Refer to the node documentation for the latest information. |
| | <note important>Note - information present in source code samples can be not up-to-date - remember to refer to the VREL node documentation for the latest information on IPs, users and passwords for both ''internal.IOT'' network access and for the NodeRED access.</note> |
| |
| MQTT broker present in the ''internal.IOT'' network is also visible under public address. So whenever you publish an MQTT message using VREL node that is connected to the ''internal.IOT'' network, you may subscribe to it using other devices connected to the ''internal.IOT'', i.e. other VREL node or if you're physically present at SUT in the IOT laboratory room 320, then you can connect your mobile and laptop to the ''internal.IOT'' network and use "internal" IP address. However, if you're in a remote location, you can access the same broker under public IP as stated in the node description. Same messages published on the internal network are also visible on the public side. Mind, to access MQTT broker you need to use IP, user and password (applies to both public and private IPs of the MQTT Broker). Refer to the node documentation for the latest information. | CoAP server data is: |
| <note important>Note - information present in source code samples can be not up-to-date - remember to refer to the VREL node documentation for the latest information on IPs, users and passwords for both ''internal.IOT'' network access and for the MQTT Broker.</note> | * IP address (implemented with NodeRED) is: ''192.168.90.5'' as seen from the ''internal.IOT'' network, or ''157.158.56.54'' when accessing from the public space; |
| | * The only implemented URI is ''""'' (simply root resource) - for other URIs you will get 4.04 (Not Found) error; |
| <note important>Note - Analog input in ESP8266 measures voltage on the pin A0, ranging from 0 to 3.3V (in reality somewhere from 0.1-0.2V to 3.2V) using 4096 distinguishable values - the A/D converter resolution is then 12bit and return values you may expect, range from 0 to 4095 - in fact they're much more narrowed.</note> | * CoAP port is ''5683'' (default); |
| |
| === Scenario === | === Scenario === |
| I this scenario, once you get connected to the WiFi as AP and then to the MQTT server to publish data, you will periodically read A0 (analogue) input of the ESP8266 and publish its RAW value to the MQTT server. You will also visualise the RAW value of the A0 input reading on the LCD screen. | I this scenario, once you get connected to the WiFi as AP and then you will make a UDP request using CoAP protocol to the NodeRED server acting as CoAP server. Please note, we do not implement here discovery services for CoAP, for simplicity and because of constrained resources, so you won't be able to use clients' CoAP discover feature. You will obtain a secret code from the server (it varies over time). As a bonus, you may try to discover the secret code generation algorithm :-). You're expected to present the results of the CoAP query on the LCD screen. |
| | To implement a CoAP client feature you will use a dedicated library ''ESP-CoAP simple library'', available via Platformio library management system. |
| |
| === Result === | === Result === |
| You should be able to read data stream via MQTT message, presenting flap position. Parallel, data should be displayed on the LCD, along with connection status. <note tip>Note - flap position refers to the airflow: you may need to control it using VREL2 and VREL4 for VREL1 and VREL3, respectively. Airflow in nodes 2 and 4 can be controlled twofold: using PWM to control fan rotation speed and using the flap to open/close air duct.</note> | You should be able to obtain a UDP message in CoAP, with the payload containing an ASCII text with secret code, and present it on the LCD screen. |
| |
| === Start === | === Start === |
| Define some identifiers to separate and update AP's SSID and passphrase easily. To format lines for the LCD, we suggest using a char buffer of 20 characters (one full line) and some 2-3 integers for iterators. Remember to declare the LCD control class in your code. You do not need to instantiate WiFi communication class - as you have only one interface here, it is singleton class you can refer directly using WiFi. Reading analogue input brings you an integer value. | Define some identifiers to separate and update AP's SSID and passphrase easily. To simplify conversion, use ''IPAddress'' class to create IP address of the CoAP server. To format lines for the LCD, we suggest using a char buffer of 20 characters (one full line) and some 2-3 integers for iterators. Remember to declare the LCD control class in your code. You do not need to instantiate WiFi communication class - as you have only one interface here, it is singleton class you can refer directly using WiFi. Reading analogue input brings you an integer value. Note, you're supposed to instantiate your MCU as AP even if using UDP communication. |
| |
| === Steps === | === Steps === |
| Following steps do not present full code - you need to supply missing parts on your own! We do not present here how to connect to the WiFi AP. If you're in doubt, rever to the U1 scenario. Please refer to scenario B1, if you need a recall on how to handle LCD screen. In case you're in doubt how to handle MQTT messages communication (here publishing/sending), please refer to the U3 scenario. | Following steps do not present full code - you need to supply missing parts on your own! We do not present here how to connect to the WiFi AP. If you're in doubt, rever to the U1 scenario. Please refer to scenario B1, if you need a recall on how to handle LCD screen. |
| == Step 1 == | == Step 1 == |
| Include all necessary libraries. We use PubSubClient library to contact MQTT broker. The minimum set here is: | Include all necessary libraries. We use ESP-CoAP simple library to contact CoAP server as a client. Note, this library also implements a CoAP server features but we do not use it in our scenario here. The minimum set here is: |
| <code c> | <code c> |
| #include <Arduino.h> | #include <Arduino.h> |
| #include <ESP8266WiFi.h> | #include <ESP8266WiFi.h> |
| #include <PubSubClient.h> | #include "coap_client.h" |
| #include <LiquidCrystal_I2C.h> | #include <LiquidCrystal_I2C.h> |
| ... | ... |
| </code> | </code> |
| There is no need to use a special library to read analogue input representing relative flap position here.\\ | |
| Declare some identifiers to let you easier handle necessary modifications and keep code clear: | Declare some identifiers and variables/class instances to let you easier handle necessary modifications and keep code clear: |
| <code c> | <code c> |
| #define wifi_ssid "internal.IOT" | #define wifi_ssid "internal.IOT" |
| #define wifi_password "IoTlab32768" | #define wifi_password "IoTlab32768" |
| #define mqtt_server "192.168.90.5" | |
| #define mqtt_user "vrel" | IPAddress ip(192,168,90,5);//take NodeRed Address |
| #define mqtt_password "vrel2018" | int port = 5683; |
| ... | ... |
| </code> | </code> |
| | |
| == Step 2 == | == Step 2 == |
| Declare some identifiers, here MQTT messages' topics, MQTT client ID and payloads for the status notification (on / off). | |
| |
| <note important>Use unique names for topics and for the MQTT client, do some random, use your MAC as part of it. It is important because MQTT broker identifies client using its name thus if your device shares name with some other that is already working, you may not get information about connection lost because another device with the same name is still active on the network. Unique topics are also essential: if you accidentally overlap, you may get an invalid reading with someone that is using the same topic but different payload.</note> | |
| |
| | Declare ''coapClient'' and WiFi client, to implement CoAP client instance, PubSubClient, initialise, instantiate and connect to the network. If in doubt, refer to the scenario U3 on how to prepare networking code for your solution: |
| <code c> | <code c> |
| // MQTT messages | ... |
| #define MQTTClientName ...<your client name>... | |
| #define analogOutTopic ...<some topic for flap>... // give it some unique topic | |
| // i.e. including your name | |
| |
| //MQTT last will | coapClient coap; |
| #define lastWillTopic ...<some topic for exposing state and last will>... | |
| // give it some unique topic | ... |
| // i.e. including your name | |
| #define lastWillMessage "off" | |
| #define mqttWelcomeMessage "on" | |
| </code> | </code> |
| |
| == Step 3 == | == Step 3 == |
| Declare WiFiCilent, PubSubClient, initialise, instantiate and connect to the network. If in doubt, refer to the scenario U3 on how to prepare networking code for your solution. | Prepare CoAP client response asynchronous handler. |
| | <note tip>CoAP uses UDP for communication, so you will be informed asynchronously, when response to your request appears. That is fully handled by asynchronous response handler and mechanism is implemented by the library.</note> |
| | |
| | <note important>As messages may come quickly in the queue (many replies) due to the heavy use or UDP nature, you are required to make a copy of the payload ASAP, best using ''memcpy'', as first operation in your asynchronous response handler.</note> |
| |
| == Step 4 == | |
| Prepare MQTT publishing code, here we publish periodically one value (flap position, relative), i.e. like this: | |
| <code c> | <code c> |
| void mqttPublish() | void callback_response(coapPacket &packet, IPAddress ip, int port); |
| { | ... |
| flap = analogRead(A0); | // coap client response callback |
| | void callback_response(coapPacket &packet, IPAddress ip, int port) { |
| if(client.connected()) | char p[packet.payloadlen + 1]; //declare local buffer for the payload |
| { | memcpy(p, packet.payload, packet.payloadlen); //quickly copy payload contents |
| client.publish(analogOutTopic, String(flap).c_str(), false); // Do not retain | p[packet.payloadlen] = NULL; |
| // messages | |
| } | //response from coap server - check if this is regular one (response to your request), or is it a ping request? |
| | if(packet.type==3 && packet.code==0){ |
| | //that means you've obtained a ping request so handle it (i.e. show on LCD) |
| | ... |
| | } |
| | ... //handle payload. |
| } | } |
| | ... |
| | </code> |
| | == Step 4 == |
| | |
| | Start your CoAP client in the ''setup()'' function: |
| | |
| | <code c> |
| | ... // remember to initialise it AFTER you make a WiFi connection, not before |
| | coap.respinse(callback_response); // add response handler |
| | coap.start(); //start coap client |
| | |
| </code> | </code> |
| <note important>Reading analogue input is pretty easy: all you need to do is to use ''analogRead(A0)''. Note, ESP8266 has only one analogue input A0.</note> | |
| |
| == Step 5 == | == Step 5 == |
| Your ''loop()'' function should include call to the aforementioned ''mqttPublish'' and printing on the LCD screen once every 5 seconds. | Your ''loop()'' function should include call to the CoAP client methods. Here we use only CoAP GET, as this is the only one implemented by the NodeRED server, we provide to you: |
| <code c> | <code c> |
| void loop() | void loop() |
| { | { |
| if (!client.connected()) { | ... |
| reconnect(); | int msgid = coap.get(ip,port,""); |
| } | bool state = coap.loop(); |
| client.loop(); | ... |
| mqttPublish(); | delay(10000); |
| sprintf(buffer,"Flap is %d ",flap); | |
| lcd.setCursor(0,2); | |
| lcd.print(buffer); | |
| delay(1000); | |
| } | } |
| </code> | </code> |
| <note warning>Mind to keep a ''delay(...)'', not to saturate MQTT broker and communication channel. Minimum reasonable delay between issuing consecutive MQTT messages is about 200ms.</note> | |
| <note tip>The ''flap'' variable is a global one, set in the ''mqttPublish'' using ''analogRead(A0)''. This way you have it set for ''sprintf'' formating function.</note> | <note warning>Mind to keep a ''delay(...)'', not to saturate NodeRED server with issuing dozens of UDP requests. Minimum reasonable delay between issuing consecutive requests is about 500ms.</note> |
| |
| === Result validation === | === Result validation === |
| Observe connection progress on the LCD via video stream. Once WiFi and MQTT are connected, you should be able to see analogue input readings on the LCD, and additionally, those should be sent over the MQTT messages to the MQTT broker. Connect your MQTT client and subscribe to your messages (you may do it using a wildcard character), i.e. with means of the MQTT spy application. Remember to connect MQTT spy to public IP address unless you're a student physically present in our laboratory room and you have direct access to the internal.IOT network. Observe data on the LCD screen the same as over MQTT messages (note, there may be a delay because of the network bottlenecks and MQTT broker load). | Observe connection progress on the LCD via video stream. Once WiFi is connected, you should be able to see secret code as a return from CoAP server. Note, you may want to implement presentation of the communication status, i.e. present ''msgid'' and state of the ''coap.loop()''. |
| |
| === FAQ === | === FAQ === |
| **I want to implement PID controller of the position of the flap, using TX air pushing node (VRELS 2 and 4). 200ms latency between consecutive reads seems too large, to implement efficient loopback. What to do?**: In this case, you should drop MQTT communication and communicate directly between nodes, i.e. your RX node (VREL1 and 3) can send a UDP message over the network. Our WiFi ''internal.IOT'' is a pretty efficient one, and should handle it with ease. | Secret changes over time so do not be surprised that you will obtain different numbers when returning to this exercise or executing in loop for a time. Note, to distinguish from random data, there is always some extra, textual message to let you be sure that server returned a value. |
| |