Implement device node registration
|Status:||In Progress||Start date:||24 Feb 2016|
|Target version:||002 - MVP|
|Severity:||02 - High|
This is the device node registering with the PiBox server.
- Device node must be configured for local network first (that's already implemented)
- At boot, the node sends a multicast message advertising its device type and version. It's IP address will be available from the multicast message (I think).
- The PiBox server picks up the multicast message and calls back to the Device Node using it's RESTful api.
- This requires an additional thread in piboxd to pick up the registrations on the multicast address.
- The device node configures itself appropriately and disables the multicast messages.
I need to define what it means to be "registered". Registration should also only occur when a user enables it on the server so we don't have random registration of rogue devices.
RM #501: Implemented multicast server for accepting device node registration requests. Added unit test to verify inbound message handling.
RM #501: Implement device registration via multicast messages and a RESTful interface.
RM #501: Add aJSON library support so the ESP8266 can send JSON messages to the server in support of registration.
#1 Updated by Hammel over 2 years ago
There should be a function that handles sending multicast packets. It tests for a flag. If the flag is not set, send the packet. If it is then skip it. The flag is set by the response from the PiBox server.
The sendRegistration() function does this:
Serial.println("Sending UDP multicast packet"); // send a reply, to the IP address and port that sent us the packet we received Udp.beginPacketMulticast(ipMulti, portMulti, WiFi.localIP()); Udp.write(byte1); Udp.write(byte2); Udp.print(ESP.getChipId(), HEX); Udp.print(":"); Udp.print(WiFi.localIP()); Udp.endPacket();
The UDP object is a WiFiUdp class, which is found here: Arduino/libraries/ESP8266WiFi/src/WiFiUdp.cpp
That class has no documentation so you'll have to read the code. There are two write() methods, one for a byte and one for a character string. So the registration protocol will either be a bit string or a character string or both.
It seems likely that the response will include a UUID for the device node but the registration won't need anything like that. It should probably send one or more bytes, with the bytes being bit fields for device type and version values. A third byte may be used for encryption info, perhaps.
There are good examples of using Multicast in C programs for both client and server on the web.
#2 Updated by Hammel over 2 years ago
- Status changed from New to In Progress
- % Done changed from 0 to 10
I added a multicast server to piboxd along with a unit test. Seems to work fine. It will call back to the sender at the following URL (via libcurl): http://<IPADDR>/im/1/registration/1, which means "registration accepted".
There is additional code that needs to go in here to remember a registration and to forget a registration if contact is lost for more than X number of pings. Plus I need a "ping" thread to go with this.
But the basic server is implemented.
#3 Updated by Hammel over 2 years ago
I just realized that device registration needs to survive a power cycle. Since PiBox is not depending on cloud-based data storage, this means a local-storage-based database has to be used. Both MySQL and sqlist are enabled in PiBox. This use-case doesn't need the power of MySQL. Even sqlite could be overkill.
A simpler solution would be to use an abstract block of name/value pairs. This could easily be done in JSON using the parson library. Data is added/removed/etc from the data block and the data block as a whole is saved to disk using a double-buffer mechanism (write to new file, save old file, move new file to old file, remove saved file) to avoid data corruption. We will never have that much information to store - even thousands of devices wouldn't be that much data and we expire old data when devices go away.
Parson is a single C file. I use it at work for a message passing library. The library wraps Parson and exposes an API that uses namespaces for name/value pairs. The same idea works here. A namespace is a device and it contains the name/value pair of data we maintain about those devices.
I can't reuse the code from work, but since I wrote it I can recreate it from scratch. It's extremely simple in our case since we drop all the message passing stuff. We just need a simplified wrapper around parson.
The bonus will be that piboxd will then have a JSON library embedded in it for other uses. And we can use the simplified data-block API I'll add for device nodes or call parson directly. Very cool.
Integration of parson for data stores is an MVP issue. It will not be implemented for proof-of-concept. In the PoC if we lose power devices have to re-register. Note that this might be something we'd want to do in MVP - reregister a device if it hasn't heard from the server in a while. But that's a power drain on the IoT device, to keep track of when it was last contacted. It wouldn't be able to run in low-power mode (unless low-power mode supports multicast).
UPDATE: duh. Parson makes perfect sense for in-memory storage too. There's no reason to write a link list library to handle new device registrations. Parson can handle that now. So I'll integrate parson now, for the IoT registration in the PoC. That will speed implementation. I'll abstract the data block later, for MVP.
#4 Updated by Hammel over 2 years ago
- % Done changed from 10 to 50
Device registration succeeded tonight. The node came up, sent a registration which the piboxd server received and the server responded by contacting the node. It wasn't a full success because there are still some bits of the two-way transaction that need cleaning up.
What's left to do:
I can't tell. I need to see it happen again but the WiFi won't connect to the local network again. This is a continuing problem that I will need to solve before I can go any further. I believe the solution will be to fix the layout of WiFi routers in my home.
#5 Updated by Hammel over 2 years ago
- Priority changed from Immediate to Normal
- Target version changed from 001 - Proof of concept to 002 - MVP
- Implement persistance in the server
- write data to file on exit
- read data from file on startup
- Implement device validation of commands using Uuid
- Implement reset
- Server sends multicast to devices
- Devices send registration requests again
None of this has to be done for the proof of concept. But it's required for MVP.
Switching to MVP for further work and lowering priority.
- % Done changed from 50 to 80
Device node registration changed dramatically. First, piboxd is now simply a responder to multicast discovery messages. This is implemented and tested against both Jarvis and sensors and is working properly.
Second, real registration between sensors and the monitor is now routed through the imrest REST API. This is mostly tested. I still need to fake availability of the imgpio and have both piboxd and imrest query the same directory for existing registrations during testing.