homieiot / homie-esp8266

đź’ˇ ESP8266 framework for Homie, a lightweight MQTT convention for the IoT
http://homieiot.github.io/homie-esp8266
MIT License
1.36k stars 307 forks source link

Revise the API #12

Closed marvinroger closed 8 years ago

marvinroger commented 8 years ago

Right now, a sample sketch looks like that:

#include <Homie.h>

const int PIN_RELAY = D1;

void inputHandler(String node, String property, String message) {
  if (node != "light" || property != "on") {
    return;
  }

  if (message == "true") {
    digitalWrite(PIN_RELAY, HIGH);
    Homie.sendProperty("light", "on", "true"); // update property, act as a feedback
  } else if (message == "false") {
    digitalWrite(PIN_RELAY, LOW);
    Homie.sendProperty("light", "on", "false");
  }
}

void setup() {
  pinMode(PIN_RELAY, OUTPUT);
  digitalWrite(PIN_RELAY, LOW);
  Homie.setFirmware("awesome-relay" ,"1.0.0");
  Homie.addNode("light", "light");
  Homie.addSubscription("light", "on");
  Homie.setInputHandler(inputHandler);
  Homie.setup();
}

void loop() {
  Homie.loop();
}

I think addNode, addSubscription and setInputHandler are kind of messy. I would see something like that instead:

#include <Homie.h>

const int PIN_RELAY = D1;

HomieNode light("light", "light");

void lightOnHandler(String message) {
  if (message == "true") {
    digitalWrite(PIN_RELAY, HIGH);
    Homie.sendProperty(light, "on", "true");
  } else if (message == "false") {
    digitalWrite(PIN_RELAY, LOW);
    Homie.sendProperty(light, "on", "false");
  }
}

void setup() {
  pinMode(PIN_RELAY, OUTPUT);
  digitalWrite(PIN_RELAY, LOW);
  Homie.setFirmware("awesome-relay" ,"1.0.0");
  light.subscribe("on", lightOnHandler);
  Homie.registerNode(light);
  Homie.setup();
}

void loop() {
  Homie.loop();
}

There are several benefits:

What do you think? @enavarro222 @furyfire

enavarro222 commented 8 years ago

:+1: looks nice. It should avoid -always the same- if/elseif in global handler.

Maybe handler could return a boolean that indicate if more specific ones should be call or not. For example on a msg:

Other good think I see is to create generic HomieNode by inheritance. For instance one can have a RelayNode, that you can use like that:

#include <Homie.h>
#include <HomieRelayNode.h>

HomieRelayNode light("light", "light", D1);

void setup() {
  Homie.setFirmware("awesome-relay" ,"1.0.0");
  light.setup(false); // set the initial state
  Homie.registerNode(light); // do the subscribe and callback binding
  Homie.setup();
}

void loop() {
  Homie.loop();
}
marvinroger commented 8 years ago

Your propagation idea is a great one! Will definitely implement it. Yes, global to property is the best option.

The inheritance idea is complicated. The simplest case implies a relay, as you show. The goal is simple: set a relay HIGH or LOW. The fact is, some relays are HIGH-active, others are LOW-active, so there is already a complexity. Homie for ESP8266 goal is to throw the network complexity away, not hardware ones - at least not for now -. ;)

BTW, to implement SSL and user/pass auth, the JSON config structure has to be changed. What do you think of:

{
  "name": "kitchen light",
  "wifi": {
    "ssid": "Network_1",
    "password": "I'm a Wi-Fi password!"
  },
  "mqtt": {
    "host": "192.168.1.10",
    "port": 35589,
    "auth": true,
    "username": "user",
    "password": "pass",
    "ssl": true,
    "fingerprint": "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C"
  },
  "ota": {
    "enabled": true,
    "host": "192.168.1.10",
    "port": 35590,
    "path": "/ota",
    "ssl": true,
    "fingerprint": "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C"
  }
}
enavarro222 commented 8 years ago

Yep, maybe inheritance is out of the scope on Homie (to keep it generic and lightweight), however it could be done in third part lib. For instance I got few devices with similar hardware (a buzzer, RGB lamps, ...). I already have some class that handle that hardware, for now the (always the same) binding with Hommie/MQTT is made by hand in the main file... It could be factorize in the hardware class (that inherit HomieNode).

New config json looks ok. It will also permit to have a ota server different of the mqtt one, that's nice.

furyfire commented 8 years ago

I implemented a proof of concept where homie would get the clock from and ntp server. This allows me to use the https://github.com/PaulStoffregen/Time and the https://github.com/PaulStoffregen/TimeAlarm modules which simplifies the main loop alot. The timemodule let's you schedule events periodically or at fixed times.

furyfire commented 8 years ago

And I just posted on the wrong issue. Disregard that last comment

marvinroger commented 8 years ago

Time was something I thinked about, thanks for that. Wrong issue as you said, but just be sure nothing fails if there is no internet connection, I want Homie-ESP8266 to be cloud-independant.

furyfire commented 8 years ago

The time.h lib simply starts the clock from UNIX epoch. Every schedule you start will simply run relative to that.

marvinroger commented 8 years ago

Both the config API and the new API with node and property levels handlers have been implemented. Examples have been updated to reflect the changes.

The next big step is the documentation.

marvinroger commented 8 years ago

The API in the README is not up-to-date about the handlers, but it works the way it is described in the first post, and as @enavarro222 said:

  • global handler is called,
  • if returns false, then node level handler is called
  • if returns false, property handler is called

This is probably not that clear, but it will be when the docs will be finished. :)

marvinroger commented 8 years ago

Docs are in place, I can close this.

enavarro222 commented 8 years ago

Nice ! good job ;)