gioblu / PJON

PJON (Padded Jittering Operative Network) is an experimental, arduino-compatible, multi-master, multi-media network protocol.
Other
2.73k stars 239 forks source link

BestPractice for Master - Slave #268

Closed akadlec closed 5 years ago

akadlec commented 5 years ago

Hi there, firstly, many thanks for this lib.

I would like to build small network of slave devices based on arduino boards and one master (gateway) device based on esp8266 casting as gateway for other services.

And i would like to ask more skilled members if they could share some best practise how to do communication. Usually i'm sending data through mqtt protocol, but what about this type of communication? Should i use JSON format? Or some strings with separators?

I would like to send something like this:

{
  device_id: 1234,
  di: 3,
  payload: true
}

or

{
  device_id: 1234,
  di: 'temp',
  payload: 24.5
  units: 'celsius'
}

and also something like heartbeat and welcome message

any advice?

gioblu commented 5 years ago

Ciao @akadlec welcome :) If you chose SoftwareBitBang strategy for communication with slaves, ESP8266, being 5v tolerant can be connected directly to devices that use 5v voltage level, keep in mind to apply current limiting resistors to protect IO pins. With 3v3 voltage level the maximum range is lower than using 5v, specially if on the other side there is a 5v device, so if your wiring is long, be sure executing a practical test if the 3v3 reaches the other end at a voltage high enough to be detected as a 1 by a receiving device.

About the format, that largely depends on the available resources in the slaves and the bandwidth your system requires to operate nominally. For example, if many nodes are present and the bandwidth available is scarse you may not be able to have the luxury of sending the measurement unit in plain text of each reading in each packet, and you may need to implement some logic on the master to ask it once and keep it in memory or save it in a db.

ModuleInterface developed by @fredilarsen is a good example of a complete and reliable implementation handling transfer of settings, inputs and outputs based on the PJON network protocol and JSON that probably should provide you with all the features required or at least some inspiration for future work.

Feel free to join our gitter room here https://gitter.im/gioblu/PJON for a synchronous chat :) Happy tinkering.

akadlec commented 5 years ago

Hi @gioblu i'm planing to use RS485 shield so the voltage levels should be solved by this shield (for teseting & dev)

I tried ModuleInterface, but i think it is not what i need, but as a example is good.

I have one question for you for right now. Is there a posibility to add another data to packet header? I would like to add unsigned int packetId to the header as mandatory field. This identifiel will be used by master and slave to determine type of the message.

gioblu commented 5 years ago

Ciao @akadlec sorry I thought you wanted to use the SoftwareBitBang strategy and so PJDL.

About the header you can include in the packet a packet identifier: https://github.com/gioblu/PJON/blob/master/documentation/configuration.md#packet-identification that is generally used to avoid packet duplications.

But If I understood correct your necessity:

determine type of the message

I think I would use the network service identifier or port: https://github.com/gioblu/PJON/blob/master/documentation/configuration.md#network-service-identification

akadlec commented 5 years ago

am i miss something, i can not make it work :/

Node is sending packet to master:

char _output_buffer[PJON_PACKET_MAX_LENGTH];
sprintf(_output_buffer, "{\"packet\":%d}", PACKET_MASTER_WAITING);

uint16_t result = bus.send_packet(PJON_BROADCAST, _output_buffer, strlen(_output_buffer));

Master handle message:

DynamicJsonBuffer _json_buffer;
JsonObject& _parsed_payload = _json_buffer.parseObject((const char *) payload);

if (!_parsed_payload.success()) {
}

and parsing is always unsuccessfull :(

even if i try to send only one char like in examples:

Node:

uint16_t result = bus.send_packet(PJON_BROADCAST, "P", 1);

Master:

if (payload[0] == "P") {
// Never happen
}
akadlec commented 5 years ago

Mabye more info from my sketch:

bus.set_receiver(_communicationReceiverHandler);

This callback is on both sides:

void _communicationReceiverHandler(
    uint8_t *payload,
    uint16_t length,
    const PJON_Packet_Info &packetInfo
) {
    DPRINT(F("[COMMUNICATION] Received data\n"));

    DynamicJsonBuffer _json_buffer;

    JsonObject& _parsed_payload = _json_buffer.parseObject((char *) payload);

    if (!_parsed_payload.success()) {
        DPRINT(F("[COMMUNICATION] Error parsing payload data\n"));
        DPRINT(F("[COMMUNICATION] Received paylodad with length: "));
        DPRINT(length);
        DPRINT(F(" & content: "));
        DPRINTLN((char *) payload);

        return;

    } else {
        DPRINT(F("[COMMUNICATION] Successfully parsed JSON\n"));
        DPRINT(F("[COMMUNICATION] Received paylodad with length: "));
        DPRINT(length);
        DPRINT(F(" & content: "));
        DPRINTLN((char *) payload);
    }

    if (_parsed_payload.containsKey("packet"))  {
        #if IS_MASTER
                char _output_buffer[PJON_PACKET_MAX_LENGTH];
                sprintf(_output_buffer, "{\"packet\":%d}", PACKET_MASTER_REPLY);
                bus.reply(_output_buffer, strlen(_output_buffer));
        #endif
    } else {
        DPRINT(F("[COMMUNICATION] Missing packet identifier\n"));
    }
}
akadlec commented 5 years ago

And slave is periodically sending init message like this:

void loop() {
    bus.update();
    bus.receive();

    DPRINT(F("[SYSTEM] Searching for master\n"));

    char _output_buffer[PJON_PACKET_MAX_LENGTH];
    sprintf(_output_buffer, "{\"packet\":%d}", PACKET_MASTER_WAITING);

    bus.send_packet(PJON_MASTER_ID, _output_buffer, strlen(_output_buffer));
}
akadlec commented 5 years ago
  1. Node send packet with content: {"packet":1}
  2. Master handle received packet with successfull parsing to json and send reply: {"packet":2}
  3. Node receive reply but is not able to parse it as valid json even the size of the string is correct 12
gioblu commented 5 years ago

Ciao @akadlec if I have understood correctly your report the packet is received by master but the function _parsed_payload.success() returns false. Have you tried to read the result without checking for its success? I see @Matheus-Garbelini have done so in the JSON LoRa example here: https://github.com/gioblu/PJON/blob/master/examples/ARDUINO/Local/ThroughLoRa/JSON/Receiver/Receiver.ino#L30

I am not sure why this occurs. Is the data received correct? May be because it does not find a 0 at the end of the string? Does it work adding a 0 as the last byte of the data?

akadlec commented 5 years ago

Hi @gioblu, thanks for pointing me to the example. I just updated json object init with this:

DynamicJsonBuffer _json_buffer(PJON_PACKET_MAX_LENGTH);

and it started to work :]

gioblu commented 5 years ago

Good 👍 thank you for reporting back @akadlec

akadlec commented 5 years ago

Hi @gioblu ok now I know that I have to watch memory usage, that is now for me a big issue. Could you recommend me how to prepare data to be send? As I wrote above, i'm using simple json structure, but the size is not good. Is there any way how to send more optimized data?

gioblu commented 5 years ago

ciao @akadlec look at this example that shows how to encode an integer in the simplest way: https://github.com/gioblu/PJON/tree/master/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues

you can compose the array as you wish and then feed it to PJON

gioblu commented 5 years ago

Ciao @akadlec , happy new year :) I will close here, feel free to reopen if required!