[
  {
    "path": ".gitignore",
    "content": "\r\n.DS_Store\r\nha_mqtt_multisensor/config.h\r\nha_mqtt_multisensor/Configuration/binary_sensor.yaml\r\nha_mqtt_multisensor/Configuration/sensor.yaml\r\nha_mqtt_sensor_dht22/config.h\r\nha_mqtt_binary_sensor_ble_scanner/config.h\r\nha_mqtt_binary_sensor_nfc_scanner/config.h\r\nha_mqtt_light_arilux/config.h\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Open Home Automation\n\n**THIS REPOSITORY IS NOT MAINTAINED ANYMORE, SEE [ESPHome](https://esphome.io/) AS AN ALTERNATIVE.**\n\n## Introduction\nNowadays everything becomes connected to the Internet and gives us a glimpse of many new possibilities. Home automation is part of it and offers many advantages for their users.\nThis repository is dedicated to [Home Assistant](https://home-assistant.io), an open source project with an amazing community, ESP8266 and ESP32 modules, the MQTT protocol and much more [...].\n\n### Home Assistant\n> Home Assistant is a home automation platform running on Python 3. The goal of Home Assistant is to be able to track and control all devices at home and offer a platform for automating control [[Home-Assistant](https://github.com/home-assistant/home-assistant)].\n\n### MQTT\n> MQTT is a machine-to-machine (M2M)/\"Internet of Things\" connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium [[mqtt.org](http://mqtt.org)].\n\n![Home-Assistant](openhome/images/Features.png)\n\n## Content\n### Requirements\nMost of the examples below are using the MQTT protocol and so require to integrate MQTT into Home Assistant by defining a MQTT broker. More information can be found at the [MQTT component's page](https://home-assistant.io/components/mqtt/).\n\n#### Stock Home Assistant\nconfiguration.yaml :\n\n```yaml\nmqtt:\n  broker: 127.0.0.1\n  port: 1883                      \n  username: '[Redacted]'\n  password: '[Redacted]'\n  discovery: true                 # optional\n  discovery_prefix: homeassistant # optional\n```\n\n#### Hass.io\nconfiguration.yaml :\n\n```yaml\nmqtt:\n  broker: core-mosquitto\n  username: '[Redacted]'\n  password: '[Redacted]'\n  discovery: true                 # optional\n  discovery_prefix: homeassistant # optional\n```\n\nMore options to connect the broker are available and described [here](https://home-assistant.io/docs/mqtt/broker/#embedded-broker).\n\n### Sketches for ESP8266/ESP32 modules\nLights, sensors, switches and more can be built on top of MQTT. This section contains a few examples based on MQTT and on a NodeMCU board (ESP8266/ESP32).\n\n| Title / link                                  | Description                                                           |\n|-----------------------------------------------|-----------------------------------------------------------------------|\n| [Light](/ha_mqtt_light)                       | A simple example to control a **led**                                 |\n| [Light](/ha_mqtt_light_with_brightness)       | A simple example to control a **led** and its brightness              |\n| [Light](/ha_mqtt_rgb_light)                   | A simple example to control a **RGB led**                             |\n| [Light](/ha_mqtt_light_with_WiFiManager_mDNS_and_OTA) | A simple example to control a **RGB led** (with **OTA** and **mDNS**)|\n| [Light](https://github.com/mertenats/Arilux_AL-LC03)| An alternative firmware for the **Arilux AL-LC0X LED controller** |\n| [Light](/ha_mqtt_light_arilux)| An alternative firmware for the **Arilux AL-LC0X LED controller** with multiple effects from the [WS2812FX](https://github.com/kitesurfer1404/WS2812FX) |\n| [Light](/ha_mqtt_rgbw_light_with_discoveryw)    | A simple example to control a **RGBW led**, based on the **MQTT JSON Light** component (brightness, rgb, white, color temperature and effects) and including the **MQTT Discovery**                         |\n| [Light](https://github.com/mertenats/AI-Thinker_RGBW_Bulb)    | An alternative firmware for **AI-Thinker RGBW bulbs**, based on the **MQTT JSON Light** component and including the **MQTT Discovery**  functionality                       |\n| [Switch](/ha_mqtt_switch)                     | A simple example to control a **switch**    \n| [Switch](https://github.com/mertenats/Itead_Sonoff/tree/master/Sonoff_Basic) | An alternative firmware for the **Sonoff Basic** switches                      |\n| [Switch](https://github.com/mertenats/Itead_Sonoff/tree/master/Sonoff_TH) | An alternative firmware for the **Sonoff TH** switches, including the **MQTT Discovery**  functionality                 |\n| [Sensor](/ha_mqtt_sensor_dht22)               | A simple example to measure the **temperature** and the **humidity** (DHT22 sensor)|\n| [Sensor](/ha_mqtt_sensor_photocell)           | A simple example to measure the **brightness** (photocell)|\n| [Binary Sensor](/ha_mqtt_binary_sensor_pir)   | A simple example to detect **motions** (PIR motion sensor)|\n| [Binary Sensor](/ha_mqtt_binary_sensor_door)  | A simple example to monitor the **state** of a **window/door** |\n| [Binary Sensor](/ha_mqtt_multisensor)         | A full example describing how to monitor your **environment** with different sensors (SHT3X, DHT22, TEMT6000, etc.)|\n| [Binary Sensor](/ha_mqtt_binary_sensor_ble_scanner)| An example describing how to trigger an action when a specific **BLE device** is detected (ESP32)|\n| [Binary Sensor](/ha_mqtt_binary_sensor_nfc_scanner)| An example describing how to trigger an action when a specific **NFC tag** is detected|\n\n### Configuration examples for Home Assistant\nThis section contains a few configuration examples dedicated to Home Assistant.\n\n| Title / link                                  | Description                                                           |\n|-----------------------------------------------|-----------------------------------------------------------------------|\n| [Alarm Clock](/ha_config_alarm_clock)         | An example describing how to create an **alarm clock** with the components provided by HA |\n| [openhome](/openhome)                         | A school project based on Home Assistant and using only **open source** HW and SW |\n| [Zigate & ZigBee devices](/ha_config_zigate)  | An example describing how to add and control **ZigBee** devices paired to a **Zigate** |\n\n[![OpenHome with Home Assistant and MQTT](openhome/images/Youtube.png)](https://www.youtube.com/watch?v=Vh-vzFPCF2U \"OpenHome with Home Assistant and MQTT\")\n\n## Miscelleneous\n\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  SOFTWARE.\n\n*If you like the content of this repo, please add a star! Thank you!*\n"
  },
  {
    "path": "ha_config_alarm_clock/README.md",
    "content": "# Configuration - Alarm Clock - Home Assistant\nA simple configuration example to create an alarm clock and trigger an automation, which turns on the light and switches on a stereo. This example was tested on [Home Assistant](https://home-assistant.io) 0.64.1 and uses the Philips [Hue](https://home-assistant.io/components/light.hue/) component and an [Onkyo](https://home-assistant.io/components/media_player.onkyo/) media player.\n\n## Configuration\nconfiguration.yaml :\n```yaml\nhomeassistant:\n  # Customization file\n  customize: !include customize.yaml\n\nhue:\n  bridges:\n   - host: 192.168.1.130\n\nrecorder:\n  include:\n    entities:\n      - input_number.alarm_clock_hours\n      - input_number.alarm_clock_minutes\n      - input_boolean.alarm_clock_status\n\nsensor: !include sensors.yaml\ninput_number: !include input_numbers.yaml\ninput_boolean: !include input_booleans.yaml\nmedia_player: !include media_players.yaml\ngroup: !include groups.yaml\nautomation: !include automations.yaml\n```\n\ncustomize.yaml :\n```yaml\ninput_number.alarm_clock_hours:\n  friendly_name: 'Heure'\n  icon: mdi:timer\ninput_number.alarm_clock_minutes:\n  friendly_name: 'Minute'\n  icon: mdi:timer\ninput_boolean.alarm_clock_status:\n  friendly_name: 'Etat'\n  icon: mdi:calendar\nsensor.alarm_clock_hours:\n  hidden: true\nsensor.alarm_clock_minutes:\n  hidden: true\nsensor.alarm_clock_time:\n  friendly_name: 'Heure du réveil'\n  icon: mdi:alarm\n```\n\nsensors.yaml :\n```yaml\n- platform: template\n  sensors:\n    alarm_clock_hours:\n      value_template: \"{{ states('input_number.alarm_clock_hours') | round(0) }}\"\n    alarm_clock_minutes:\n      value_template: \"{{ states('input_number.alarm_clock_minutes') | round(0) }}\"\n    alarm_clock_time:\n      value_template: \"{% if states.sensor.alarm_clock_hours.state | length == 1 -%}0{%- endif -%}{{ states.sensor.alarm_clock_hours.state }}:{% if states.sensor.alarm_clock_minutes.state | length == 1 -%}0{%- endif -%}{{ states.sensor.alarm_clock_minutes.state }}\"\n- platform: time_date\n  display_options:\n    - 'time'\n```\n\ninput_numbers.yaml :\n```yaml\nalarm_clock_hours:\n  min: 0\n  max: 23\n  step: 1\n  mode: slider\nalarm_clock_minutes:\n  min: 0\n  max: 55\n  step: 5\n  mode: slider\n```\n\ninput_booleans.yaml :\n```yaml\nalarm_clock_status:\n```\n\nmedia_players.yaml :\n```yaml\n- platform: onkyo\n  host: 192.168.1.133\n  name: 'Stereo'\n```\n\ngroups.yaml :\n```yaml\ndefault_view:\n  view: yes\n  entities:\n    - group.alarm_clock\n\nalarm_clock:\n  name: 'Réveil'\n  entities:\n    - sensor.alarm_clock_time\n    - input_number.alarm_clock_hours\n    - input_number.alarm_clock_minutes\n    - input_boolean.alarm_clock_status\n```\n\nautomations.yaml :\n```yaml\n- alias: 'Turn on the alarm clock'\n  trigger:\n    platform: template\n    value_template: '{{ states.sensor.time.state == states.sensor.alarm_clock_time.state }}'\n  condition:\n    condition: and\n    conditions:\n     - condition: state\n       entity_id: input_boolean.alarm_clock_status\n       state: 'on'\n     - condition: time\n       weekday:\n         - mon\n         - tue\n         - wed\n         - thu\n         - fri\n  action:\n    - service: media_player.turn_on\n      data:\n        entity_id: media_player.stereo\n    - service: media_player.volume_set\n      data:\n        entity_id: media_player.stereo\n        volume_level: 0.07\n    - service: media_player.select_source\n      data:\n        entity_id: media_player.stereo\n        source: dab\n    - service: light.turn_on\n      data:\n        entity_id: light.bedside\n        brightness: 255\n        transition: 900\n    - delay:\n        minutes: 15\n    - service: light.turn_on\n      data:\n        entity_id: light.ceiling\n        brightness: 255\n    - service: light.turn_off\n      data:\n        entity_id: light.bedside\n```\n\n## Preview\n![Alarm Clock](Alarm_clock.png)\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/automations.yaml",
    "content": "- alias: 'Turn on the alarm clock'\n  trigger:\n    platform: template\n    value_template: '{{ states.sensor.time.state == states.sensor.alarm_clock_time.state }}'\n  condition:\n    condition: and\n    conditions:\n     - condition: state\n       entity_id: input_boolean.alarm_clock_status\n       state: 'on'\n     - condition: time\n       weekday:\n         - mon\n         - tue\n         - wed\n         - thu\n         - fri\n  action:\n    - service: media_player.turn_on\n      data:\n        entity_id: media_player.stereo\n    - service: media_player.volume_set\n      data:\n        entity_id: media_player.stereo\n        volume_level: 0.07\n    - service: media_player.select_source\n      data:\n        entity_id: media_player.stereo\n        source: dab\n    - service: light.turn_on\n      data:\n        entity_id: light.bedside\n        brightness: 255\n        transition: 900\n    - delay:\n        minutes: 15\n    - service: light.turn_on\n      data:\n        entity_id: light.ceiling\n        brightness: 255\n    - service: light.turn_off\n      data:\n        entity_id: light.bedside\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/configuration.yaml",
    "content": "homeassistant:\n  # Customization file\n  customize: !include customize.yaml\n\nhue:\n  bridges:\n   - host: 192.168.1.130\n\nrecorder:\n  include:\n    entities:\n      - input_number.alarm_clock_hours\n      - input_number.alarm_clock_minutes\n      - input_boolean.alarm_clock_status\n\nsensor: !include sensors.yaml\ninput_number: !include input_numbers.yaml\ninput_boolean: !include input_booleans.yaml\nmedia_player: !include media_players.yaml\ngroup: !include groups.yaml\nautomation: !include automations.yaml\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/customize.yaml",
    "content": "input_number.alarm_clock_hours:\n  friendly_name: 'Heure'\n  icon: mdi:timer\ninput_number.alarm_clock_minutes:\n  friendly_name: 'Minute'\n  icon: mdi:timer\ninput_boolean.alarm_clock_status:\n  friendly_name: 'Status'\n  icon: mdi:calendar\nsensor.alarm_clock_hours:\n  hidden: true\nsensor.alarm_clock_minutes:\n  hidden: true\nsensor.alarm_clock_time:\n  friendly_name: 'Réveil'\n  icon: mdi:alarm\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/groups.yaml",
    "content": "default_view:\n  view: yes\n  entities:\n    - group.alarm_clock\n\nalarm_clock:\n  name: 'Réveil'\n  entities:\n    - sensor.alarm_clock_time\n    - input_number.alarm_clock_hours\n    - input_number.alarm_clock_minutes\n    - input_boolean.alarm_clock_status\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/input_booleans.yaml",
    "content": "alarm_clock_status:\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/input_numbers.yaml",
    "content": "alarm_clock_hours:\n  min: 0\n  max: 23\n  step: 1\n  mode: slider\nalarm_clock_minutes:\n  min: 0\n  max: 55\n  step: 5\n  mode: slider\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/media_players.yaml",
    "content": "- platform: onkyo\n  host: 192.168.1.133\n  name: 'Stereo'\n"
  },
  {
    "path": "ha_config_alarm_clock/configuration/sensors.yaml",
    "content": "- platform: template\n  sensors:\n    alarm_clock_hours:\n      value_template: \"{{ states('input_number.alarm_clock_hours') | round(0) }}\"\n    alarm_clock_minutes:\n      value_template: \"{{ states('input_number.alarm_clock_minutes') | round(0) }}\"\n    alarm_clock_time:\n      value_template: \"{% if states.sensor.alarm_clock_hours.state | length == 1 -%}0{%- endif -%}{{ states.sensor.alarm_clock_hours.state }}:{% if states.sensor.alarm_clock_minutes.state | length == 1 -%}0{%- endif -%}{{ states.sensor.alarm_clock_minutes.state }}\"\n- platform: time_date\n  display_options:\n    - 'time'\n"
  },
  {
    "path": "ha_config_zigate/README.md",
    "content": "# Configuration - Zigate and ZigBee devices - Home Assistant\nA simple configuration example to add and control ZigBee devices paired to a [Zigate](https://zigate.fr), an open source ZigBee concentrator.\n\n## Requirements\n### Software\nUsing the Zigate with Home Assistant requires to install `pyzigate` ([GitHub](https://github.com/elric91/ZiGate)) and copy the `homeassistant_zigate` component within the `custom_components` in Home Assistant's configuration folder ([GitHub](https://github.com/elric91/homeassistant_zigate)).\n\n### Hardware\n- 1x [Zigate](https://zigate.fr)\n- 2x Philips white bulbs\n- 1x Xiaomi Aqara switch\n- 1x Xiaomi Aqara door sensor\n- 1x Xiaomi Aqara temperature/humidity/pressure sensor\n\n## Configuration\nconfiguration.yaml :\n```yaml\nhomeassistant:\n\n...\n\nswitch: !include switches.yaml\nlight: !include lights.yaml\nsensor: !include sensors.yaml\nautomation: !include automations.yaml\n```\n\nConfiguration for the Xiaomi Aqara door sensor :\n\nswitches.yaml :\n```yaml\n- platform: zigate\n  name: 'Door'\n  address: XXXX01\n  default_state: 'state'\n  inverted: 'yes'\n```\n\nConfiguration for the two white Philips Hue bulbs :\n\nlights.yaml :\n```yaml\n- platform: zigate\n  name: 'Bedside'\n  address: XXXX0b\n  light_type: 'white'\n  default_state: 'event'\n- platform: zigate\n  name: 'Ceiling'\n  address: XXXX0b\n  light_type: 'white'\n  default_state: 'event'\n```\n**Note** : Philips uses the `0b`cluster for their bulbs!\n\nConfiguration for the Xiaomi Aqara temperature/humidity/pressure sensor and switch :\n\nsensors.yaml :\n```yaml\n- platform: zigate\n  name: 'Ceiling Switch'\n  address: XXXX01\n  default_state: 'state'\n- platform: zigate\n  name: 'Temperature'\n  address: XXXX01\n  default_state: temperature\n  default_unit: '°C'\n- platform: zigate\n  name: 'Humidity'\n  address: XXXX01\n  default_state: humidity\n  default_unit: '%'\n- platform: zigate\n  name: 'Pressure'\n  address: XXXX01\n  default_state: pressure\n  default_unit: 'mb'\n```\n\nAutomation example to handle a single/double click on the Xiaomi Aqara switch :\n\nautomations.yaml :\n```yaml\n- alias: 'Ceiling Switch - Single Click'\n  hide_entity: True\n  trigger:\n    entity_id: sensor.ceiling_switch\n    platform: state\n    to: 'off-release'\n  action:\n    service: light.toggle\n    data:\n      entity_id: light.ceiling\n- alias: 'Ceiling Switch - Double Click'\n  hide_entity: True\n  trigger:\n    entity_id: sensor.ceiling_switch\n    platform: state\n    to: 'multi_2'\n  action:\n    service: light.toggle\n    data:\n      entity_id: light.bedside\n```\n\n## References\n- [Instructions pour les ampoules Philips Hue](http://zigate.fr/837-2/)\n- [Configuration examples](https://github.com/elric91/homeassistant_zigate/wiki/Configuration-examples)\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_ble_scanner/README.md",
    "content": "# MQTT Binary Sensor - Bluetooth LE Device Tracker - Home Assistant\nA simple example describing how to track a Bluetooth Low Energy device with an ESP32, the MQTT protocol and Home Assistant. Please note that the targeted device can't have a changing BLE address (normally called random instead of public address).  \n\n![ESP32](esp32.jpg)\n\n## Configuration\nTo configure this sketch, you have to rename the header file `example.config.h` in `config.h`, provide the Bluetooth device(s) to track and add your Wi-Fi and MQTT credentials in the `SOFTWARE SECTION`.\n\n### Bluetooth Device(s)\n```\n#define NB_OF_BLE_TRACKED_DEVICES 1\nBLETrackedDevice BLETrackedDevices[NB_OF_BLE_TRACKED_DEVICES] = {\n  {\"11:22:33:44:55:66\", false, 0, false, {0}}\n};\n\n// Location of the BLE scanner\n#define LOCATION \"bedroom\"\n```\nor with multiple devices\n```\n#define NB_OF_BLE_TRACKED_DEVICES 3\nBLETrackedDevice BLETrackedDevices[NB_OF_BLE_TRACKED_DEVICES] = {\n  {\"11:22:33:44:55:66\", false, 0, false, {0}},\n  {\"11:22:33:44:55:66\", false, 0, false, {0}},\n  {\"11:22:33:44:55:66\", false, 0, false, {0}}\n};\n\n// Location of the BLE scanner\n#define LOCATION \"bedroom\"\n```\n\n### Credentials\n```\n// Wi-Fi credentials\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n// MQTT\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n```\n\n### Home Assistant\nTo add the occupancy sensor to Home Assistant, please edit and add this snippet into your configuration. Make sure to replace `<CHIP_ID`, `<LOCATION>` and `<BLE_ADDRESS>` with the values defined in `config.h`.\n\n```yaml\n# Example configuration.yaml entry\nbinary_sensor:\n  - platform: mqtt\n    name: 'Occupancy'\n    state_topic: '<CHIP_ID>/sensor/<LOCATION>/<BLE_ADDRESS>/state'\n    availability_topic: '<CHIP_ID/availability'\n    device_class: occupancy\n```\n\n![Occupancy](occupancy.png)\n\n## Licence\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  SOFTWARE.\n\n*If you like the content of this repo, please add a star! Thank you!*\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_ble_scanner/example.config.h",
    "content": "///////////////////////////////////////////////////////////////////////////\n//  CONFIGURATION - SOFTWARE\n///////////////////////////////////////////////////////////////////////////\n#define NB_OF_BLE_TRACKED_DEVICES 1\nBLETrackedDevice BLETrackedDevices[NB_OF_BLE_TRACKED_DEVICES] = {\n  {\"11:22:33:44:55:66\", false, 0, false, {0}}\n};\n\n#define BLE_SCANNING_PERIOD   5\n#define MAX_NON_ADV_PERIOD    10000\n\n// Location of the BLE scanner\n#define LOCATION \"bedroom\"\n\n// Debug output\n//#define DEBUG_SERIAL\n\n// Wi-Fi credentials\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n// Over-the-Air update\n// Not implemented yet\n//#define OTA\n//#define OTA_HOSTNAME  \"\"    // hostname esp8266-[ChipID] by default\n//#define OTA_PASSWORD  \"\"    // no password by default\n//#define OTA_PORT      8266  // port 8266 by default\n\n// MQTT\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n\n#define MQTT_CONNECTION_TIMEOUT 5000 // [ms]\n\n// MQTT availability: available/unavailable\n#define MQTT_AVAILABILITY_TOPIC_TEMPLATE  \"%s/availability\" \n// MQTT binary sensor: <CHIP_ID>/sensor/<LOCATION>/<BLE_ADDRESS>\n#define MQTT_SENSOR_TOPIC_TEMPLATE        \"%s/sensor/%s/%s/state\"\n\n#define MQTT_PAYLOAD_ON   \"ON\"\n#define MQTT_PAYLOAD_OFF  \"OFF\"\n\n#define MQTT_PAYLOAD_AVAILABLE    \"online\"\n#define MQTT_PAYLOAD_UNAVAILABLE  \"offline\"\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_ble_scanner/ha_mqtt_binary_sensor_ble_scanner.ino",
    "content": "/*\n  MQTT Binary Sensor - Bluetooth LE Device Tracker - Home Assistant\n  \n  Libraries:\n    - PubSubClient: https://github.com/knolleary/pubsubclient\n    - ESP32 BLE:    https://github.com/nkolban/ESP32_BLE_Arduino\n\n  Sources:\n    - https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/examples/BLE_scan/BLE_scan.ino\n    - https://www.youtube.com/watch?v=KNoFdKgvskU\n\n  Samuel M. - v1.0 - 01.2018\n  If you like this example, please add a star! Thank you!\n  https://github.com/mertenats/open-home-automation\n*/\n\ntypedef struct {\n  String  address;\n  bool    isDiscovered;\n  long    lastDiscovery;\n  bool    toNotify;\n  char    mqttTopic[48];\n} BLETrackedDevice;\n\n#include \"config.h\"\n#include <BLEDevice.h>\n#include <WiFi.h>\n#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient\n\n#if defined(DEBUG_SERIAL)\n#define     DEBUG_PRINT(x)    Serial.print(x)\n#define     DEBUG_PRINTLN(x)  Serial.println(x)\n#else\n#define     DEBUG_PRINT(x)\n#define     DEBUG_PRINTLN(x)\n#endif\n\nBLEScan*      pBLEScan;\nWiFiClient    wifiClient;\nPubSubClient  mqttClient(wifiClient);\n\n///////////////////////////////////////////////////////////////////////////\n//   BLUETOOTH\n///////////////////////////////////////////////////////////////////////////\nclass MyAdvertisedDeviceCallbacks:\n  public BLEAdvertisedDeviceCallbacks {\n    void onResult(BLEAdvertisedDevice advertisedDevice) {\n      for (uint8_t i = 0; i < NB_OF_BLE_TRACKED_DEVICES; i++) {\n        if (strcmp(advertisedDevice.getAddress().toString().c_str(), BLETrackedDevices[i].address.c_str()) == 0) {\n          if (!BLETrackedDevices[i].isDiscovered) {\n            BLETrackedDevices[i].isDiscovered = true;\n            BLETrackedDevices[i].lastDiscovery = millis();\n            BLETrackedDevices[i].toNotify = true;\n\n            DEBUG_PRINT(F(\"INFO: Tracked device newly discovered, Address: \"));\n            DEBUG_PRINT(advertisedDevice.getAddress().toString().c_str());\n            DEBUG_PRINT(F(\", RSSI: \"));\n            DEBUG_PRINTLN(advertisedDevice.getRSSI());\n          } else {\n            BLETrackedDevices[i].lastDiscovery = millis();\n            DEBUG_PRINT(F(\"INFO: Tracked device discovered, Address: \"));\n            DEBUG_PRINT(advertisedDevice.getAddress().toString().c_str());\n            DEBUG_PRINT(F(\", RSSI: \"));\n            DEBUG_PRINTLN(advertisedDevice.getRSSI());\n          }\n        } else {\n          DEBUG_PRINT(F(\"INFO: Device discovered, Address: \"));\n          DEBUG_PRINT(advertisedDevice.getAddress().toString().c_str());\n          DEBUG_PRINT(F(\", RSSI: \"));\n          DEBUG_PRINTLN(advertisedDevice.getRSSI());\n        }\n      }\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////\n//   MQTT\n///////////////////////////////////////////////////////////////////////////\nvolatile unsigned long lastMQTTConnection = 0;\nchar MQTT_CLIENT_ID[7] = {0};\nchar MQTT_AVAILABILITY_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_AVAILABILITY_TOPIC_TEMPLATE) - 2] = {0};\n/*\n  Function called to publish to a MQTT topic with the given payload\n*/\nvoid publishToMQTT(char* p_topic, char* p_payload) {\n  if (mqttClient.publish(p_topic, p_payload, true)) {\n    DEBUG_PRINT(F(\"INFO: MQTT message published successfully, topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\", payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  } else {\n    DEBUG_PRINTLN(F(\"ERROR: MQTT message not published, either connection lost, or message too large. Topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\" , payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  }\n}\n/*\n  Function called to connect/reconnect to the MQTT broker\n*/\nvoid connectToMQTT() {\n  if (!mqttClient.connected()) {\n    if (lastMQTTConnection < millis()) {\n      if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD, MQTT_AVAILABILITY_TOPIC, 0, 1, MQTT_PAYLOAD_UNAVAILABLE)) {\n        DEBUG_PRINTLN(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n        publishToMQTT(MQTT_AVAILABILITY_TOPIC, MQTT_PAYLOAD_AVAILABLE);\n      } else {\n        DEBUG_PRINTLN(F(\"ERROR: The connection to the MQTT broker failed\"));\n        DEBUG_PRINT(F(\"INFO: MQTT username: \"));\n        DEBUG_PRINTLN(MQTT_USERNAME);\n        DEBUG_PRINT(F(\"INFO: MQTT password: \"));\n        DEBUG_PRINTLN(MQTT_PASSWORD);\n        DEBUG_PRINT(F(\"INFO: MQTT broker: \"));\n        DEBUG_PRINTLN(MQTT_SERVER);\n      }\n      lastMQTTConnection = millis() + MQTT_CONNECTION_TIMEOUT;\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   SETUP() & LOOP()\n///////////////////////////////////////////////////////////////////////////\nvoid setup() {\n#if defined(DEBUG_SERIAL)\n  Serial.begin(115200);\n#endif\n\n  BLEDevice::init(\"\");\n  pBLEScan = BLEDevice::getScan();\n  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());\n  pBLEScan->setActiveScan(false);\n\n  mqttClient.setServer(MQTT_SERVER, MQTT_SERVER_PORT);\n\n  sprintf(MQTT_CLIENT_ID, \"%06X\", ESP.getEfuseMac());\n  sprintf(MQTT_AVAILABILITY_TOPIC, MQTT_AVAILABILITY_TOPIC_TEMPLATE, MQTT_CLIENT_ID);\n\n  DEBUG_PRINT(F(\"INFO: MQTT availability topic: \"));\n  DEBUG_PRINTLN(MQTT_AVAILABILITY_TOPIC);\n\n  char mqttTopic[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(LOCATION) + 12 - 4] = {0};\n  for (uint8_t i = 0; i < NB_OF_BLE_TRACKED_DEVICES; i++) {\n      char tmp_ble_address[13] = {0};\n      String tmp_string_ble_address = BLETrackedDevices[i].address;\n      tmp_string_ble_address.replace(\":\", \"\");\n      tmp_string_ble_address.toCharArray(tmp_ble_address, sizeof(tmp_ble_address));\n      sprintf(mqttTopic, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, LOCATION, tmp_ble_address);\n      memcpy(BLETrackedDevices[i].mqttTopic, mqttTopic, sizeof(mqttTopic) + 1);\n      DEBUG_PRINT(F(\"INFO: MQTT sensor topic: \"));\n      DEBUG_PRINTLN(BLETrackedDevices[i].mqttTopic);\n  }\n\n}\n\nvoid loop() {\n  pBLEScan->start(BLE_SCANNING_PERIOD);\n\n  static boolean enableWifi = false;\n  for (uint8_t i = 0; i < NB_OF_BLE_TRACKED_DEVICES; i++) {\n    if (BLETrackedDevices[i].toNotify) {\n      enableWifi = true;\n    } else if (BLETrackedDevices[i].isDiscovered == true && BLETrackedDevices[i].lastDiscovery + MAX_NON_ADV_PERIOD < millis()) {\n      BLETrackedDevices[i].isDiscovered = false;\n      BLETrackedDevices[i].toNotify = true;\n      enableWifi = true;\n    }\n  }\n\n  if (enableWifi) {\n    enableWifi = false;\n\n    DEBUG_PRINT(F(\"INFO: WiFi connecting to: \"));\n    DEBUG_PRINTLN(WIFI_SSID);\n    delay(10);\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n    randomSeed(micros());\n    \n    while (WiFi.status() != WL_CONNECTED) {\n      DEBUG_PRINT(F(\".\"));\n      delay(500);\n    }\n    DEBUG_PRINTLN();\n    DEBUG_PRINTLN(WiFi.localIP());\n\n    while (!mqttClient.connected()) {\n      connectToMQTT();\n    }\n\n    for (uint8_t i = 0; i < NB_OF_BLE_TRACKED_DEVICES; i++) {\n      if (BLETrackedDevices[i].toNotify) {\n        if (BLETrackedDevices[i].isDiscovered) {\n          publishToMQTT(BLETrackedDevices[i].mqttTopic, MQTT_PAYLOAD_ON);\n        } else {\n          publishToMQTT(BLETrackedDevices[i].mqttTopic, MQTT_PAYLOAD_OFF);\n        }\n        BLETrackedDevices[i].toNotify = false;\n      }\n    }\n\n    mqttClient.disconnect();\n    WiFi.mode(WIFI_OFF);\n  }\n}\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_door/README.md",
    "content": "# MQTT Binary Sensor - Door - Home Assistant\nA simple example to monitor the state of a door with a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nbinary_sensor:\n  platform: mqtt\n  name: 'Door'\n  state_topic: 'CBF777/binary_sensor/door/state'\n  sensor_class: opening\n```\n\n## Schematic\nDoor sensor\n- Door sensor leg 1 - D1\n- Door sensor leg 2 - GND\n\nButton\n- Switch leg 1 - VCC\n- Switch leg 2 - D2 - Resistor 10K Ohms - GND\n\n## Wi-Fi and MQTT Configuration\n![Steps](Steps.png)\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_door/ha_mqtt_binary_sensor_door.ino",
    "content": "/* \n  MQTT Binary Sensor - Door sensor for Home-Assistant - NodeMCU (ESP8266)\n  https://home-assistant.io/components/binary_sensor.mqtt/\n  \n  Libraries :\n    - ESP8266 core for Arduino :  https://github.com/esp8266/Arduino\n    - PubSubClient:               https://github.com/knolleary/pubsubclient\n    - WiFiManager:                https://github.com/tzapu/WiFiManager\n  \n  Sources :\n    - File > Examples > ES8266WiFi > WiFiClient\n    - File > Examples > PubSubClient > mqtt_auth\n\n  Steps:\n    - Upload the firmware\n    - Connect to the new Wi-Fi AP and memorize its name \n    - Choose your network and enter your MQTT username, password, broker \n      IP address and broker port\n    - Update your configuration in Home Assistant\n\n  Configuration (Home Assistant) : \n    binary_sensor:\n      platform: mqtt\n      name: 'Door'\n      state_topic: 'CBF777/binary_sensor/door/state'\n      sensor_class: opening\n\n  Samuel M. - v1.0 - 11.2016\n  If you like this example, please add a star! Thank you!\n  https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>    // https://github.com/esp8266/Arduino\n#include <WiFiManager.h>    // https://github.com/tzapu/WiFiManager\n#include <PubSubClient.h>   // https://github.com/knolleary/pubsubclient/releases/tag/v2.6\n#include <Ticker.h>\n#include <EEPROM.h>\n#include <ArduinoOTA.h>\n\n#define               DEBUG                       // enable debugging\n#define               STRUCT_CHAR_ARRAY_SIZE 24   // size of the arrays for MQTT username, password, etc.\n\n// macros for debugging\n#ifdef DEBUG\n  #define             DEBUG_PRINT(x)    Serial.print(x)\n  #define             DEBUG_PRINTLN(x)  Serial.println(x)\n#else\n  #define             DEBUG_PRINT(x)\n  #define             DEBUG_PRINTLN(x)\n#endif\n\n// Pins used by the door sensor and the push button\nconst PROGMEM uint8_t DOOR_SENSOR_PIN = D1;\nconst PROGMEM uint8_t BUTTON_PIN      = D2;\nconst PROGMEM uint8_t BUILTINLED_PIN  = BUILTIN_LED;\n\n// MQTT ID and topics\nchar                  MQTT_CLIENT_ID[7]                                           = {0};\nchar                  MQTT_BINARY_SENSOR_DOOR_STATE_TOPIC[STRUCT_CHAR_ARRAY_SIZE] = {0};\nconst char*           MQTT_ON_PAYLOAD                                             = \"ON\";\nconst char*           MQTT_OFF_PAYLOAD                                            = \"OFF\";\n\n// MQTT settings\ntypedef struct {\n  char                mqttUser[STRUCT_CHAR_ARRAY_SIZE]      = {0};\n  char                mqttPassword[STRUCT_CHAR_ARRAY_SIZE]  = {0};\n  char                mqttServer[STRUCT_CHAR_ARRAY_SIZE]    = {0};\n  char                mqttPort[5]                           = {0};\n} Settings;\n\nuint8_t               doorState             = LOW;\nuint8_t               currentDoorState      = doorState;\nuint8_t               buttonState           = LOW;\nuint8_t               currentButtonState    = buttonState;\nlong                  buttonStartPressed    = 0;\nlong                  buttonDurationPressed = 0;\n\nenum CMD {\n  CMD_NOT_DEFINED,\n  CMD_DOOR_STATE_CHANGED,\n  CMD_BUTTON_STATE_CHANGED,\n};\nvolatile uint8_t cmd = CMD_NOT_DEFINED;\n\nSettings      settings;\nTicker        ticker;\nWiFiClient    wifiClient;\nPubSubClient  mqttClient(wifiClient);\n\n\n///////////////////////////////////////////////////////////////////////////\n//   MQTT\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to publish the state of the door sensor\n*/\nvoid publishDoorState() {\n  if (doorState == HIGH) {\n    if (mqttClient.publish(MQTT_BINARY_SENSOR_DOOR_STATE_TOPIC, MQTT_ON_PAYLOAD, true)) {\n      DEBUG_PRINT(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      DEBUG_PRINT(MQTT_BINARY_SENSOR_DOOR_STATE_TOPIC);\n      DEBUG_PRINT(F(\". Payload: \"));\n      DEBUG_PRINTLN(MQTT_ON_PAYLOAD);\n    } else {\n      DEBUG_PRINTLN(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n    }\n  } else {\n    if (mqttClient.publish(MQTT_BINARY_SENSOR_DOOR_STATE_TOPIC, MQTT_OFF_PAYLOAD, true)) {\n      DEBUG_PRINT(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      DEBUG_PRINT(MQTT_BINARY_SENSOR_DOOR_STATE_TOPIC);\n      DEBUG_PRINT(F(\". Payload: \"));\n      DEBUG_PRINTLN(MQTT_OFF_PAYLOAD);\n    } else {\n      DEBUG_PRINTLN(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n    }\n  }\n}\n\n/*\n  Function called to connect/reconnect to the MQTT broker\n*/\nvoid reconnect() {\n  uint8_t i = 0;\n  while (!mqttClient.connected()) {\n    if (mqttClient.connect(MQTT_CLIENT_ID, settings.mqttUser, settings.mqttPassword)) {\n      DEBUG_PRINTLN(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n    } else {\n      DEBUG_PRINTLN(F(\"ERROR: The connection to the MQTT broker failed\"));\n      DEBUG_PRINT(F(\"Username: \"));\n      DEBUG_PRINTLN(settings.mqttUser);\n      DEBUG_PRINT(F(\"Password: \"));\n      DEBUG_PRINTLN(settings.mqttPassword);\n      DEBUG_PRINT(F(\"Broker: \"));\n      DEBUG_PRINTLN(settings.mqttServer);\n      delay(1000);\n      if (i == 3) {\n        reset();\n      }\n      i++;\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   WiFiManager\n///////////////////////////////////////////////////////////////////////////\n/*\n  Function called to toggle the state of the LED\n*/\nvoid tick() {\n  digitalWrite(BUILTIN_LED, !digitalRead(BUILTIN_LED));\n}\n\n// flag for saving data\nbool shouldSaveConfig = false;\n\n// callback notifying us of the need to save config\nvoid saveConfigCallback () {\n  shouldSaveConfig = true;\n}\n\nvoid configModeCallback (WiFiManager *myWiFiManager) {\n  ticker.attach(0.2, tick);\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   ISR\n///////////////////////////////////////////////////////////////////////////\n/*\n  Function called when the door is opened/closed\n*/\nvoid doorStateChangedISR() {\n  cmd = CMD_DOOR_STATE_CHANGED;\n}\n\n/*\n  Function called when the button is pressed/released\n*/\nvoid buttonStateChangedISR() {\n  cmd = CMD_BUTTON_STATE_CHANGED;\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   ESP\n///////////////////////////////////////////////////////////////////////////\n/*\n  Function called to restart the switch\n*/\nvoid restart() {\n  DEBUG_PRINTLN(F(\"INFO: Restart...\"));\n  ESP.reset();\n  delay(1000);\n}\n\n/*\n  Function called to reset the configuration of the switch\n*/\nvoid reset() {\n  DEBUG_PRINTLN(F(\"INFO: Reset...\"));\n  WiFi.disconnect();\n  delay(1000);\n  ESP.reset();\n  delay(1000);\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   Setup() and loop()\n///////////////////////////////////////////////////////////////////////////\nvoid setup() {\n#ifdef DEBUG\n  Serial.begin(115200);\n#endif\n  pinMode(DOOR_SENSOR_PIN,  INPUT_PULLUP);\n  pinMode(BUTTON_PIN,       INPUT);\n  pinMode(BUILTIN_LED,      OUTPUT);\n\n  attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR_PIN), doorStateChangedISR,    CHANGE);\n  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN),      buttonStateChangedISR,  CHANGE);\n\n  ticker.attach(0.6, tick);\n\n  sprintf(MQTT_CLIENT_ID, \"%06X\", ESP.getChipId());\n  DEBUG_PRINT(F(\"INFO: MQTT client ID/Hostname: \"));\n  DEBUG_PRINTLN(MQTT_CLIENT_ID);\n\n  sprintf(MQTT_BINARY_SENSOR_DOOR_STATE_TOPIC, \"%06X/binary_sensor/door/state\", ESP.getChipId());\n  DEBUG_PRINT(F(\"INFO: MQTT command topic: \"));\n  DEBUG_PRINTLN(MQTT_BINARY_SENSOR_DOOR_STATE_TOPIC);\n\n  // load custom params\n  EEPROM.begin(512);\n  EEPROM.get(0, settings);\n  EEPROM.end();\n\n  WiFiManagerParameter custom_mqtt_user(\"mqtt-user\", \"MQTT User\", settings.mqttUser, STRUCT_CHAR_ARRAY_SIZE);\n  WiFiManagerParameter custom_mqtt_password(\"mqtt-password\", \"MQTT Password\", settings.mqttPassword, STRUCT_CHAR_ARRAY_SIZE, \"type = \\\"password\\\"\");\n  WiFiManagerParameter custom_mqtt_server(\"mqtt-server\", \"MQTT Broker IP\", settings.mqttServer, STRUCT_CHAR_ARRAY_SIZE);\n  WiFiManagerParameter custom_mqtt_port(\"mqtt-port\", \"MQTT Broker Port\", settings.mqttPort, 5);\n\n  WiFiManager wifiManager;\n\n  wifiManager.addParameter(&custom_mqtt_user);\n  wifiManager.addParameter(&custom_mqtt_password);\n  wifiManager.addParameter(&custom_mqtt_server);\n  wifiManager.addParameter(&custom_mqtt_port);\n\n  wifiManager.setAPCallback(configModeCallback);\n  wifiManager.setConfigPortalTimeout(180);\n  // set config save notify callback\n  wifiManager.setSaveConfigCallback(saveConfigCallback);\n\n  if (!wifiManager.autoConnect(MQTT_CLIENT_ID)) {\n    ESP.reset();\n    delay(1000);\n  }\n\n  if (shouldSaveConfig) {\n    strcpy(settings.mqttServer,   custom_mqtt_server.getValue());\n    strcpy(settings.mqttPort,     custom_mqtt_port.getValue());\n    strcpy(settings.mqttUser,     custom_mqtt_user.getValue());\n    strcpy(settings.mqttPassword, custom_mqtt_password.getValue());\n\n    EEPROM.begin(512);\n    EEPROM.put(0, settings);\n    EEPROM.end();\n  }\n\n  // configure MQTT\n  mqttClient.setServer(settings.mqttServer, atoi(settings.mqttPort));\n\n  // connect to the MQTT broker\n  reconnect();\n\n  ArduinoOTA.setHostname(MQTT_CLIENT_ID);\n  ArduinoOTA.begin();\n\n  ticker.detach();\n\n  doorState = digitalRead(DOOR_SENSOR_PIN);\n  buttonState = digitalRead(BUTTON_PIN);\n  digitalWrite(BUILTIN_LED, HIGH);\n\n  publishDoorState();\n}\n\nvoid loop() {\n  ArduinoOTA.handle();\n\n  yield();\n\n  // keep the MQTT client connected to the broker\n  if (!mqttClient.connected()) {\n    reconnect();\n  }\n  mqttClient.loop();\n\n  yield();\n\n  switch (cmd) {\n    case CMD_NOT_DEFINED:\n      // do nothing ...\n      break;\n    case CMD_DOOR_STATE_CHANGED:\n      currentDoorState = digitalRead(DOOR_SENSOR_PIN);\n      if (doorState != currentDoorState) {\n        if (currentDoorState == HIGH) {\n          DEBUG_PRINTLN(F(\"INFO: Door opened\"));\n        } else {\n          DEBUG_PRINTLN(F(\"INFO: Door closed\"));\n        }\n        doorState = currentDoorState;\n      }\n      publishDoorState();\n      cmd = CMD_NOT_DEFINED;\n      break;\n    case CMD_BUTTON_STATE_CHANGED:\n      currentButtonState = digitalRead(BUTTON_PIN);\n      if (buttonState != currentButtonState) {\n        // tests if the button is released or pressed\n        if (buttonState == HIGH && currentButtonState == LOW) {\n          buttonDurationPressed = millis() - buttonStartPressed;\n          if (buttonDurationPressed < 500) {\n            // do nothing\n            DEBUG_PRINTLN(F(\"INFO: Single press\"));\n          } else if (buttonDurationPressed < 3000) {\n            DEBUG_PRINTLN(F(\"INFO: Restarting...\"));\n            restart();\n          } else {\n            DEBUG_PRINTLN(F(\"INFO: Reseting...\"));\n            reset();\n          }\n        } else if (buttonState == LOW && currentButtonState == HIGH) {\n          buttonStartPressed = millis();\n        }\n        buttonState = currentButtonState;\n      }\n      cmd = CMD_NOT_DEFINED;\n      break;\n  }\n}\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_nfc_scanner/README.md",
    "content": "# MQTT Binary Sensor - NFC Tags Scanner - Home Assistant\nA simple example describing how to scan NFC tags with an ESP8266 and send the results through MQTT to Home Assistant.\n\n![NFC](nfc_scanner.jpg)\n\n## Schematic\nRequirements :\n- PN532 NFC RFID (Elechouse module v3)\n- ESP8266 (NodeMCU v1.0)\n\n| NFC reader | NodeMCU / ESP8266  |\n|------------|--------------------|\n| SS (CS)    | D2 (GPIO4)         |\n| SCK        | D5 (GPIO14)        |\n| MISO       | D6 (GPIO12)        |\n| MOSI       | D7 (GPIO13)        |\n| VCC        | VCC (3V3)          |\n| GND        | GND                |\n\n## Configuration\nTo configure this sketch, you have to rename the header file `example.config.h` in `config.h`, provide the NFC tag's UID to track, its desired name (for example `MifareTag`) and add your Wi-Fi and MQTT credentials in the `SOFTWARE SECTION`.\n\n### NFC Tags\n```\n#define NB_OF_NFC_TRACKED_TAGS 1\nNFCTag NFCTags[NB_OF_NFC_TRACKED_TAGS] = {\n  {{0x11, 0x22, 0x33, 0x44, 0x0, 0x0, 0x0}, \"MifareTag\", false, 0, false, {0}}\n};\n\n// Location of the NFC scanner\n#define LOCATION \"office\"\n```\nor with multiple tags\n```\n#define NB_OF_NFC_TRACKED_TAGS 2\nNFCTag NFCTags[NB_OF_NFC_TRACKED_TAGS] = {\n  {{0x11, 0x22, 0x33, 0x44, 0x0, 0x0, 0x0}, \"MifareTag\", false, 0, false, {0}},\n  {{0x12, 0x23, 0x34, 0x45, 0x0, 0x0, 0x0}, \"MifareCard\", false, 0, false, {0}},\n};\n```\n\n### Credentials\n```\n// Wi-Fi credentials\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n// MQTT\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n```\n\n### Home Assistant\nTo retrieve and use the results obtained with the NFC scanner into Home Assistant, please edit and add this snippet into your configuration. Make sure to replace `<CHIP_ID`, `<LOCATION>` and `<NFC_TAG_NAME>` with the values defined in `config.h`.\n\n```yaml\n# Example configuration.yaml entry\nbinary_sensor:\n  - platform: mqtt\n    name: 'NFC Tag'\n    state_topic: '<CHIP_ID>/sensor/<LOCATION>/<NFC_TAG_NAME>/state'\n    availability_topic: '<CHIP_ID>/availability'\n  - platform: mqtt\n    name: 'NFC Card'\n    state_topic: '<CHIP_ID>/sensor/<LOCATION>/<NFC_TAG_NAME>/state'\n    availability_topic: '<CHIP_ID>/availability'\n```\n\n![HA](ha.png)\n\n## Licence\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  SOFTWARE.\n\n*If you like the content of this repo, please add a star! Thank you!*\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_nfc_scanner/example.config.h",
    "content": "///////////////////////////////////////////////////////////////////////////\n//  CONFIGURATION - SOFTWARE\n///////////////////////////////////////////////////////////////////////////\n#define NB_OF_NFC_TRACKED_TAGS 2\nNFCTag NFCTags[NB_OF_NFC_TRACKED_TAGS] = {\n  {{0x11, 0x22, 0x33, 0x44, 0x0, 0x0, 0x0}, \"MifareTag\", false, 0, false, {0}},\n  {{0x12, 0x23, 0x34, 0x45, 0x0, 0x0, 0x0}, \"MifareCard\", false, 0, false, {0}},\n};\n\n// send OFF payload after x ms\n#define MAX_NON_DISCOVERED_PERIOD 1000\n\n// Location of the BLE scanner\n#define LOCATION \"office\"\n\n// Debug output\n#define DEBUG_SERIAL\n\n// Wi-Fi credentials\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n// MQTT\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n\n#define MQTT_CONNECTION_TIMEOUT 5000 // [ms]\n\n// MQTT availability: available/unavailable\n#define MQTT_AVAILABILITY_TOPIC_TEMPLATE  \"%s/availability\"\n// MQTT binary sensor: <CHIP_ID>/sensor/<LOCATION>/<BLE_ADDRESS>\n#define MQTT_SENSOR_TOPIC_TEMPLATE        \"%s/sensor/%s/%s/state\"\n\n#define MQTT_PAYLOAD_ON   \"ON\"\n#define MQTT_PAYLOAD_OFF  \"OFF\"\n\n#define MQTT_PAYLOAD_AVAILABLE    \"online\"\n#define MQTT_PAYLOAD_UNAVAILABLE  \"offline\"\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_nfc_scanner/ha_mqtt_binary_sensor_nfc_scanner.ino",
    "content": "/*\n  MQTT Binary Sensor - NFC Tags Scanner - Home Assistant\n  \n  Libraries:\n    - PubSubClient: https://github.com/knolleary/pubsubclient\n    - PN532:        https://github.com/Seeed-Studio/PN532\n\n  Sources:\n    - Examples > PN532 > readMifare \n\n  Samuel M. - v1.0 - 02.2018\n  If you like this example, please add a star! Thank you!\n  https://github.com/mertenats/open-home-automation\n*/\n\ntypedef struct {\n  uint8_t uid[7];\n  String  tagName;\n  bool    isDiscovered;\n  long    lastDiscovery;\n  bool    toNotify;\n  char    mqttTopic[48];\n} NFCTag;\n\n#include \"config.h\"\n#include <ESP8266WiFi.h>\n#include <SPI.h>\n#include <PN532_SPI.h>\n#include \"PN532.h\"        // https://github.com/Seeed-Studio/PN532\n#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient\n\n#if defined(DEBUG_SERIAL)\n#define     DEBUG_PRINT(x)    Serial.print(x)\n#define     DEBUG_PRINTLN(x)  Serial.println(x)\n#else\n#define     DEBUG_PRINT(x)\n#define     DEBUG_PRINTLN(x)\n#endif\n\nWiFiClient    wifiClient;\nPubSubClient  mqttClient(wifiClient);\nPN532_SPI     pn532spi(SPI, 4);\nPN532         nfc(pn532spi);\n\n///////////////////////////////////////////////////////////////////////////\n//   NFC\n///////////////////////////////////////////////////////////////////////////\nvoid readNFCTag() {\n  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID\n  uint8_t uidLength;\n  \n  if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {\n    for (uint8_t i = 0; i < NB_OF_NFC_TRACKED_TAGS; i++) {\n      if (strcmp((char *)uid, (char *)NFCTags[i].uid) == 0) {\n        if (!NFCTags[i].isDiscovered) {\n          NFCTags[i].isDiscovered = true;\n          NFCTags[i].toNotify = true;\n        }\n        NFCTags[i].lastDiscovery = millis();\n        break;\n      }\n    }\n  }\n  \n  for (uint8_t i = 0; i < NB_OF_NFC_TRACKED_TAGS; i++) {\n    if (NFCTags[i].isDiscovered == true && NFCTags[i].lastDiscovery + MAX_NON_DISCOVERED_PERIOD < millis()) {\n      NFCTags[i].isDiscovered = false;\n      NFCTags[i].toNotify = true;\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   WiFi\n///////////////////////////////////////////////////////////////////////////\n/*\n   Function called to handle WiFi events\n*/\nvoid handleWiFiEvent(WiFiEvent_t event) {\n  switch (event) {\n    case WIFI_EVENT_STAMODE_GOT_IP:\n      DEBUG_PRINTLN(F(\"INFO: Connection successful to the Wi-Fi AP\"));\n      DEBUG_PRINT(F(\"INFO: IP address: \"));\n      DEBUG_PRINTLN(WiFi.localIP());\n      break;\n    case WIFI_EVENT_STAMODE_DISCONNECTED:\n      DEBUG_PRINTLN(F(\"ERROR: Connection lost from the Wi-Fi AP\"));\n      /*\n         TODO: Doing something smarter than rebooting the device\n      */\n      delay(5000);\n      ESP.restart();\n      break;\n    default:\n      DEBUG_PRINT(F(\"INFO: WiFi event: \"));\n      DEBUG_PRINTLN(event);\n      break;\n  }\n}\n\n/*\n   Function called to setup the connection to the WiFi AP\n*/\nvoid setupWiFi() {\n  DEBUG_PRINT(F(\"INFO: WiFi connecting to: \"));\n  DEBUG_PRINTLN(WIFI_SSID);\n\n  delay(10);\n\n  WiFi.mode(WIFI_STA);\n  WiFi.onEvent(handleWiFiEvent);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  randomSeed(micros());\n}\n///////////////////////////////////////////////////////////////////////////\n//   MQTT\n///////////////////////////////////////////////////////////////////////////\nvolatile unsigned long lastMQTTConnection = 0;\nchar MQTT_CLIENT_ID[7] = {0};\nchar MQTT_AVAILABILITY_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_AVAILABILITY_TOPIC_TEMPLATE) - 2] = {0};\n/*\n  Function called to publish to a MQTT topic with the given payload\n*/\nvoid publishToMQTT(char* p_topic, char* p_payload) {\n  if (mqttClient.publish(p_topic, p_payload, true)) {\n    DEBUG_PRINT(F(\"INFO: MQTT message published successfully, topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\", payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  } else {\n    DEBUG_PRINTLN(F(\"ERROR: MQTT message not published, either connection lost, or message too large. Topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\" , payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  }\n}\n/*\n  Function called to connect/reconnect to the MQTT broker\n*/\nvoid connectToMQTT() {\n  if (!mqttClient.connected()) {\n    if (lastMQTTConnection < millis()) {\n      if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD, MQTT_AVAILABILITY_TOPIC, 0, 1, MQTT_PAYLOAD_UNAVAILABLE)) {\n        DEBUG_PRINTLN(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n        publishToMQTT(MQTT_AVAILABILITY_TOPIC, MQTT_PAYLOAD_AVAILABLE);\n      } else {\n        DEBUG_PRINTLN(F(\"ERROR: The connection to the MQTT broker failed\"));\n        DEBUG_PRINT(F(\"INFO: MQTT username: \"));\n        DEBUG_PRINTLN(MQTT_USERNAME);\n        DEBUG_PRINT(F(\"INFO: MQTT password: \"));\n        DEBUG_PRINTLN(MQTT_PASSWORD);\n        DEBUG_PRINT(F(\"INFO: MQTT broker: \"));\n        DEBUG_PRINTLN(MQTT_SERVER);\n      }\n      lastMQTTConnection = millis() + MQTT_CONNECTION_TIMEOUT;\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   SETUP() & LOOP()\n///////////////////////////////////////////////////////////////////////////\nvoid setup() {\n#if defined(DEBUG_SERIAL)\n  Serial.begin(115200);\n#endif\n\n  setupWiFi();\n\n  nfc.begin();\n \n  uint32_t nfcReaderFirmwareVersion = nfc.getFirmwareVersion();\n  if (!nfcReaderFirmwareVersion) {\n    DEBUG_PRINTLN(F(\"ERROR: Didn't find PN53x board\"));\n    while (1); // halt\n  }\n  \n  // configure board to read RFID tags\n  nfc.SAMConfig();\n  \n  sprintf(MQTT_CLIENT_ID, \"%06X\", ESP.getChipId());\n  sprintf(MQTT_AVAILABILITY_TOPIC, MQTT_AVAILABILITY_TOPIC_TEMPLATE, MQTT_CLIENT_ID);\n\n  DEBUG_PRINT(F(\"INFO: MQTT availability topic: \"));\n  DEBUG_PRINTLN(MQTT_AVAILABILITY_TOPIC);\n\n  char mqttTopic[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(LOCATION) + 12 - 4] = {0};\n  for (uint8_t i = 0; i < NB_OF_NFC_TRACKED_TAGS; i++) {\n      char tmpTagName[sizeof(NFCTags[i].tagName)] = {0};\n      NFCTags[i].tagName.toCharArray(tmpTagName, sizeof(tmpTagName));\n      sprintf(mqttTopic, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, LOCATION, tmpTagName);\n      memcpy(NFCTags[i].mqttTopic, mqttTopic, sizeof(mqttTopic) + 1);\n      DEBUG_PRINT(F(\"INFO: MQTT sensor topic: \"));\n      DEBUG_PRINTLN(NFCTags[i].mqttTopic);\n  }\n  \n  mqttClient.setServer(MQTT_SERVER, MQTT_SERVER_PORT);\n  connectToMQTT();\n}\n\nvoid loop() {\n  connectToMQTT();\n  mqttClient.loop();\n\n  yield();\n\n  readNFCTag();\n\n  yield();\n\n  for (uint8_t i = 0; i < NB_OF_NFC_TRACKED_TAGS; i++) {\n    if (NFCTags[i].toNotify) {\n      if (NFCTags[i].isDiscovered) {\n        publishToMQTT(NFCTags[i].mqttTopic, MQTT_PAYLOAD_ON);\n      } else {\n        publishToMQTT(NFCTags[i].mqttTopic, MQTT_PAYLOAD_OFF);\n      }\n      NFCTags[i].toNotify = false;\n    }\n  }\n  \n  yield();\n}\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_pir/README.md",
    "content": "# MQTT Binary Sensor - Motion - Home Assistant\nA simple example to use a PIR motion sensor connected to a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nbinary_sensor:\n  platform: mqtt\n  state_topic: 'office/motion/status'\n  name: 'Motion'\n  sensor_class: motion\n```\n\n## Schematic\n- PIR leg 1 - VCC\n- PIR leg 2 - D1/GPIO5\n- PIR leg 3 - GND\n\n![Schematic](Schematic.png)\n"
  },
  {
    "path": "ha_mqtt_binary_sensor_pir/ha_mqtt_binary_sensor_pir.ino",
    "content": "/*\n   MQTT Binary Sensor - Motion (PIR) for Home-Assistant - NodeMCU (ESP8266)\n   https://home-assistant.io/components/binary_sensor.mqtt/\n\n   Libraries :\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n\n   Sources :\n    - File > Examples > ES8266WiFi > WiFiClient\n    - File > Examples > PubSubClient > mqtt_auth\n    - File > Examples > PubSubClient > mqtt_esp8266\n    - https://learn.adafruit.com/pir-passive-infrared-proximity-motion-sensor/using-a-pir\n\n   Schematic :\n    - https://github.com/mertenats/open-home-automation/blob/master/ha_mqtt_binary_sensor_pir/Schematic.png\n    - PIR leg 1 - VCC\n    - PIR leg 2 - D1/GPIO5\n    - PIR leg 3 - GND\n    \n   Configuration (HA) : \n     binary_sensor:\n      platform: mqtt\n      state_topic: 'office/motion/status'\n      name: 'Motion'\n      sensor_class: motion\n      \n   TODO :\n    - Use the interrupts instead of constinously polling the sensor\n\n   Samuel M. - v1.1 - 08.2016\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wifi: SSID and password\nconst PROGMEM char* WIFI_SSID = \"[Redacted]\";\nconst PROGMEM char* WIFI_PASSWORD = \"[Redacted]\";\n\n// MQTT: ID, server IP, port, username and password\nconst PROGMEM char* MQTT_CLIENT_ID = \"office_motion\";\nconst PROGMEM char* MQTT_SERVER_IP = \"[Redacted]\";\nconst PROGMEM uint16_t MQTT_SERVER_PORT = 1883;\nconst PROGMEM char* MQTT_USER = \"[Redacted]\";\nconst PROGMEM char* MQTT_PASSWORD = \"[Redacted]\";\n\n// MQTT: topic\nconst PROGMEM char* MQTT_MOTION_STATUS_TOPIC = \"office/motion/status\";\n\n// default payload\nconst PROGMEM char* MOTION_ON = \"ON\";\nconst PROGMEM char* MOTION_OFF = \"OFF\";\n\n// PIR : D1/GPIO5\nconst PROGMEM uint8_t PIR_PIN = 5;\nuint8_t m_pir_state = LOW; // no motion detected\nuint8_t m_pir_value = 0;\n\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\n\n// function called to publish the state of the pir sensor\nvoid publishPirSensorState() {\n  if (m_pir_state) {\n    client.publish(MQTT_MOTION_STATUS_TOPIC, MOTION_OFF, true);\n  } else {\n    client.publish(MQTT_MOTION_STATUS_TOPIC, MOTION_ON, true);\n  }\n}\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n}\n\nvoid reconnect() {\n  // Loop until we're reconnected\n  while (!client.connected()) {\n    Serial.println(\"INFO: Attempting MQTT connection...\");\n    // Attempt to connect\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {\n      Serial.println(\"INFO: connected\");\n    } else {\n      Serial.print(\"ERROR: failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\"DEBUG: try again in 5 seconds\");\n      // Wait 5 seconds before retrying\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  // init the serial\n  Serial.begin(115200);\n\n  // init the WiFi connection\n  Serial.println();\n  Serial.println();\n  Serial.print(\"INFO: Connecting to \");\n  Serial.println(WIFI_SSID);\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n\n  Serial.println(\"\");\n  Serial.println(\"INFO: WiFi connected\");\n  Serial.println(\"INFO: IP address: \");\n  Serial.println(WiFi.localIP());\n\n  // init the MQTT connection\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n\n  // read the PIR sensor\n  m_pir_value = digitalRead(PIR_PIN);\n  if (m_pir_value == HIGH) {\n    if (m_pir_state == LOW) {\n      // a motion is detected\n      Serial.println(\"INFO: Motion detected\");\n      publishPirSensorState();\n      m_pir_state = HIGH;\n    }\n  } else {\n    if (m_pir_state == HIGH) {\n      publishPirSensorState();\n      Serial.println(\"INFO: Motion ended\");\n      m_pir_state = LOW;\n    }\n  }\n}\n"
  },
  {
    "path": "ha_mqtt_light/README.md",
    "content": "# MQTT Light - Home Assistant\nA simple example to control a led connected to a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nlight:\n  platform: mqtt\n  name: 'Office light'\n  state_topic: 'office/light1/status'\n  command_topic: 'office/light1/switch'\n  optimistic: false\n```\n\n## Schematic\n- GND - LED - Resistor 220 Ohms - D1/GPIO5\n\n![Schematic](Schematic.png)\n"
  },
  {
    "path": "ha_mqtt_light/ha_mqtt_light.ino",
    "content": "/*\n   MQTT Light for Home-Assistant - NodeMCU (ESP8266)\n   https://home-assistant.io/components/light.mqtt/\n\n   Libraries :\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n\n   Sources :\n    - File > Examples > ES8266WiFi > WiFiClient\n    - File > Examples > PubSubClient > mqtt_auth\n    - File > Examples > PubSubClient > mqtt_esp8266\n\n   Schematic :\n    - https://github.com/mertenats/open-home-automation/blob/master/ha_mqtt_light/Schematic.png\n    - GND - LED - Resistor 220 Ohms - D1/GPIO5\n\n   Configuration (HA) : \n    light:\n      platform: mqtt\n      name: Office light'\n      state_topic: 'office/light1/status'\n      command_topic: 'office/light1/switch'\n      optimistic: false\n\n   Samuel M. - v1.1 - 08.2016\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wifi: SSID and password\nconst char* WIFI_SSID = \"[Redacted]\";\nconst char* WIFI_PASSWORD = \"[Redacted]\";\n\n// MQTT: ID, server IP, port, username and password\nconst PROGMEM char* MQTT_CLIENT_ID = \"office_light1\";\nconst PROGMEM char* MQTT_SERVER_IP = \"[Redacted]\";\nconst PROGMEM uint16_t MQTT_SERVER_PORT = 1883;\nconst PROGMEM char* MQTT_USER = \"[Redacted]\";\nconst PROGMEM char* MQTT_PASSWORD = \"[Redacted]\";\n\n// MQTT: topics\nconst char* MQTT_LIGHT_STATE_TOPIC = \"office/light1/status\";\nconst char* MQTT_LIGHT_COMMAND_TOPIC = \"office/light1/switch\";\n\n// payloads by default (on/off)\nconst char* LIGHT_ON = \"ON\";\nconst char* LIGHT_OFF = \"OFF\";\n\nconst PROGMEM uint8_t LED_PIN = 5;\nboolean m_light_state = false; // light is turned off by default\n\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\n\n// function called to publish the state of the light (on/off)\nvoid publishLightState() {\n  if (m_light_state) {\n    client.publish(MQTT_LIGHT_STATE_TOPIC, LIGHT_ON, true);\n  } else {\n    client.publish(MQTT_LIGHT_STATE_TOPIC, LIGHT_OFF, true);\n  }\n}\n\n// function called to turn on/off the light\nvoid setLightState() {\n  if (m_light_state) {\n    digitalWrite(LED_PIN, HIGH);\n    Serial.println(\"INFO: Turn light on...\");\n  } else {\n    digitalWrite(LED_PIN, LOW);\n    Serial.println(\"INFO: Turn light off...\");\n  }\n}\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n  // concat the payload into a string\n  String payload;\n  for (uint8_t i = 0; i < p_length; i++) {\n    payload.concat((char)p_payload[i]);\n  }\n  \n  // handle message topic\n  if (String(MQTT_LIGHT_COMMAND_TOPIC).equals(p_topic)) {\n    // test if the payload is equal to \"ON\" or \"OFF\"\n    if (payload.equals(String(LIGHT_ON))) {\n      if (m_light_state != true) {\n        m_light_state = true;\n        setLightState();\n        publishLightState();\n      }\n    } else if (payload.equals(String(LIGHT_OFF))) {\n      if (m_light_state != false) {\n        m_light_state = false;\n        setLightState();\n        publishLightState();\n      }\n    }\n  }\n}\n\nvoid reconnect() {\n  // Loop until we're reconnected\n  while (!client.connected()) {\n    Serial.println(\"INFO: Attempting MQTT connection...\");\n    // Attempt to connect\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {\n      Serial.println(\"INFO: connected\");\n      // Once connected, publish an announcement...\n      publishLightState();\n      // ... and resubscribe\n      client.subscribe(MQTT_LIGHT_COMMAND_TOPIC);\n    } else {\n      Serial.print(\"ERROR: failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\"DEBUG: try again in 5 seconds\");\n      // Wait 5 seconds before retrying\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  // init the serial\n  Serial.begin(115200);\n\n  // init the led\n  pinMode(LED_PIN, OUTPUT);\n  analogWriteRange(255);\n  setLightState();\n\n  // init the WiFi connection\n  Serial.println();\n  Serial.println();\n  Serial.print(\"INFO: Connecting to \");\n  WiFi.mode(WIFI_STA);\n  Serial.println(WIFI_SSID);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n\n  Serial.println(\"\");\n  Serial.println(\"INFO: WiFi connected\");\n  Serial.print(\"INFO: IP address: \");\n  Serial.println(WiFi.localIP());\n\n  // init the MQTT connection\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n}\n"
  },
  {
    "path": "ha_mqtt_light_arilux/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Samuel Mertenat\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "ha_mqtt_light_arilux/README.md",
    "content": "# MQTT Light - Arilux - Home Assistant\nThis sketch is an alternative firmware for Arilux LED controllers, based on the [WS2812FX](https://github.com/kitesurfer1404/WS2812FX) library and is compatible with `Home Assistant` through the `MQTT` protocol. \n\n## Configuration\nTo configure this sketch, you have to rename the header file `example.config.h` in `config.h`. Then, it is possible to modify the `name` and the `location` of the device or edit your Wi-Fi and MQTT credentials. Note that the device `name` and `location` are used to create the MQTT topics.\n\n### Device location and name\n```\n#define DEVICE_LOCATION \"bedroom\"\n#define DEVICE_NAME     \"arilux\" // also used as MQTT ID\n```\n\n### Credentials\nWi-Fi :\n\n```\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n```\nMQTT :\n\n```\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n```\n\n### Home Assistant\nTo integrate the light in Home Assistant, please edit and add this snippet into your configuration.\n\n```yaml\n# Example configuration.yml entry\nlight:\n  - platform: mqtt\n    schema: json\n    state_topic: 'bedroom/arilux/state'\n    command_topic: 'bedroom/arilux/set'\n    brightness: true\n    rgb: true\n    white_value: true\n    effect: true\n    effect_list: \n      - 'Static'\n      - 'Blink'\n      - 'Breath'\n      - 'Random Color'\n      - 'Rainbow'\n      - 'Fade'\n      - 'Strobe'\n      - 'Strobe Rainbow'\n      - 'Multi Strobe'\n      - 'Blink Rainbow'\n      - 'Comet'\n      - 'Fire Flicker'\n      - 'Halloween'\n```\n\n## Flash the firmware and control\nMore information available [here](https://github.com/mertenats/Arilux_AL-LC0X).\n\nExample of a returned state :\n```\n{\n  \"state\" : \"ON\",\n  \"brightness\" : 255,\n  \"color\" : {\n    \"r\" : 0,\n    \"g\" : 250,\n    \"b\" : 0\n  },\n  \"white_value\" : 0,\n  \"effect\" : \"Static\"\n}\n```\n\n## Licence\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  SOFTWARE.\n\n*If you like the content of this repo, please add a star! Thank you!*\n"
  },
  {
    "path": "ha_mqtt_light_arilux/example.config.h",
    "content": "///////////////////////////////////////////////////////////////////////////////////////////////\n// WIFI\n///////////////////////////////////////////////////////////////////////////////////////////////\n\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n\n///////////////////////////////////////////////////////////////////////////////////////////////\n// DEVICE\n///////////////////////////////////////////////////////////////////////////////////////////////\n\n#define DEVICE_LOCATION \"bedroom\"\n#define DEVICE_NAME     \"arilux\" // also used as MQTT ID\n\n\n///////////////////////////////////////////////////////////////////////////////////////////////\n// MQTT\n///////////////////////////////////////////////////////////////////////////////////////////////\n\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n\n// MQTT topics\n//   - status state\n//       < DEVICE_LOCATION >/< DEVICE_NAME >/state\n//   - command \n//       < DEVICE_LOCATION >/< DEVICE_NAME >/set\n//   ...\n#define MQTT_AVAILABILITY_TOPIC   DEVICE_LOCATION \"/\" DEVICE_NAME\n#define MQTT_STATE_TOPIC          DEVICE_LOCATION \"/\" DEVICE_NAME \"/state\"\n#define MQTT_CMD_TOPIC            DEVICE_LOCATION \"/\" DEVICE_NAME \"/set\"\n\n#define MQTT_STATE_ON_PAYLOAD   \"ON\"\n#define MQTT_STATE_OFF_PAYLOAD  \"OFF\"\n\n#define MQTT_AVAILABLE_PAYLOAD      \"online\"\n#define MQTT_NOT_AVAILABLE_PAYLOAD  \"offline\"\n\n\n///////////////////////////////////////////////////////////////////////////////////////////////\n// ARILUX\n///////////////////////////////////////////////////////////////////////////////////////////////\n\n#define RED_PIN       5\n#define GREEN_PIN     14\n#define BLUE_PIN      12\n#define WHITE_PIN     13\n\n#define PWM_MAX       255\n#define PWM_MIN       0\n#define PWM_FREQUENCY 500\n"
  },
  {
    "path": "ha_mqtt_light_arilux/ha_mqtt_light_arilux.ino",
    "content": "/*\n  MQTT Light for Home-Assistant - Arilux (ESP8266)\n   \n  Libraries :\n    - ESP8266 Core : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n    - WS2812FX :     https://github.com/kitesurfer1404/WS2812FX\n    - ArduinoJson :  https://github.com/bblanchon/ArduinoJson\n\n  Configuration for Home Assistant :\n  light:\n    - platform: mqtt\n      schema: json\n      state_topic: 'bedroom/arilux/state'\n      command_topic: 'bedroom/arilux/set'\n      brightness: true\n      rgb: true\n      white_value: true\n      effect: true\n      effect_list: \n        - 'Static'\n        - 'Blink'\n        - 'Breath'\n        - 'Random Color'\n        - 'Rainbow'\n        - 'Fade'\n        - 'Strobe'\n        - 'Strobe Rainbow'\n        - 'Multi Strobe'\n        - 'Blink Rainbow'\n        - 'Comet'\n        - 'Fire Flicker'\n        - 'Halloween'\n\n   Samuel M. - v1.0 - 01.2019\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n \n#include <ArduinoOTA.h>\n#include <PubSubClient.h>   // https://github.com/knolleary/pubsubclient\n#include <ArduinoJson.h>    // https://github.com/bblanchon/ArduinoJson\n#include <WS2812FX.h>       // https://github.com/kitesurfer1404/WS2812FX\n\n#include \"config.h\"\n\nstruct RGBW {\n  uint8_t red;\n  uint8_t green;\n  uint8_t blue;\n  uint8_t white;\n  bool    isWhiteSelected;\n  uint8_t brightness;\n};\n\nWiFiClient    wifiClient;\nPubSubClient  mqttClient(wifiClient);\nWS2812FX      ws2812fx = WS2812FX(1, NULL, NEO_RGBW);\nRGBW          rgbw = {PWM_MIN,PWM_MIN,PWM_MIN,PWM_MIN,false,PWM_MAX};\n\nlong lastReconnectAttempt = 0;\nbool newStateToPublish = false;\n\n///////////////////////////////////////////////////////////////////////////////////////////////\n// LIGHT\n///////////////////////////////////////////////////////////////////////////////////////////////\nuint8_t getRedValueFromRGB(uint32_t p_color) {return p_color >> 16;}\nuint8_t getGreenValueFromRGB(uint32_t p_color) {return p_color >> 8;}\nuint8_t getBlueValueFromRGB(uint32_t p_color) {return p_color;}\n\nvoid customShow(void) {\n  // get the current color \n  uint32 rgb = ws2812fx.getPixelColor(0);\n  \n  // retrieve the value for each channel\n  rgbw.red =    getRedValueFromRGB(rgb);\n  rgbw.green =  getGreenValueFromRGB(rgb);\n  rgbw.blue =   getBlueValueFromRGB(rgb);\n  \n  // set each channel with the new value\n  analogWrite(RED_PIN,    map(rgbw.red,   PWM_MIN, PWM_MAX, PWM_MIN, rgbw.brightness));\n  analogWrite(GREEN_PIN,  map(rgbw.green, PWM_MIN, PWM_MAX, PWM_MIN, rgbw.brightness));\n  analogWrite(BLUE_PIN,   map(rgbw.blue,  PWM_MIN, PWM_MAX, PWM_MIN, rgbw.brightness));\n  analogWrite(WHITE_PIN,  map(rgbw.white, PWM_MIN, PWM_MAX, PWM_MIN, rgbw.brightness));\n}\n\nvoid setupLight(void) {\n  // set the pins as output\n  pinMode(RED_PIN,    OUTPUT);\n  pinMode(GREEN_PIN,  OUTPUT);\n  pinMode(BLUE_PIN,   OUTPUT);\n  pinMode(WHITE_PIN,  OUTPUT);\n  \n  analogWriteFreq(PWM_FREQUENCY);\n  analogWriteRange(PWM_MAX);\n\n  ws2812fx.init();\n  ws2812fx.setColor(GREEN);\n  ws2812fx.stop();\n  ws2812fx.setCustomShow(customShow);\n}\n\n\n///////////////////////////////////////////////////////////////////////////////////////////////\n// MQTT\n///////////////////////////////////////////////////////////////////////////////////////////////\n\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {  \n  String topic(p_topic);\n\n  if (topic.equals(MQTT_CMD_TOPIC)) {    \n    DynamicJsonBuffer dynamicJsonBuffer;\n    JsonObject& root = dynamicJsonBuffer.parseObject(p_payload);\n \n    // check if the payload contains a new state\n    if (root.containsKey(\"state\")) {\n      if (strcmp(root[\"state\"], MQTT_STATE_ON_PAYLOAD) == 0) {\n        if (ws2812fx.isRunning() == false) {\n          if (rgbw.isWhiteSelected == true) {\n            rgbw.white = PWM_MAX;\n          }\n\n          ws2812fx.start();\n          newStateToPublish = true;\n        }\n      } else if (strcmp(root[\"state\"], MQTT_STATE_OFF_PAYLOAD) == 0) {\n        if (ws2812fx.isRunning() == true) {\n          if (rgbw.isWhiteSelected == true) {\n            rgbw.white = PWM_MIN;\n          }\n          \n          ws2812fx.stop();\n          newStateToPublish = true;\n        }\n      }\n    }\n\n    // check if the payload contains a new color value\n    if (root.containsKey(\"color\")) {\n      uint8_t red = root[\"color\"][\"r\"];\n      uint8_t green = root[\"color\"][\"g\"];\n      uint8_t blue = root[\"color\"][\"b\"];\n      \n      if ((red >= PWM_MIN || red <= PWM_MAX) && (green >= PWM_MIN || green <= PWM_MAX) && (blue >= PWM_MIN || blue <= PWM_MAX)) {\n        rgbw.white = PWM_MIN;\n        rgbw.isWhiteSelected = false;\n        ws2812fx.setMode(FX_MODE_STATIC);\n        ws2812fx.setColor(red, green, blue);\n        newStateToPublish = true;\n      }\n    }\n    \n    // check if the payload contains a new brightness value\n    if (root.containsKey(\"brightness\")) {\n      uint8_t brightness = root[\"brightness\"];\n      \n      if (brightness >= PWM_MIN || brightness <= PWM_MAX) {\n        rgbw.brightness = brightness;\n        newStateToPublish = true;\n      }\n    }\n\n    // check if the payload contains a new white value\n    if (root.containsKey(\"white_value\")) {\n      uint8_t white_value = root[\"white_value\"];\n      \n      if (white_value >= PWM_MIN || white_value <= PWM_MAX) {\n        rgbw.white = PWM_MAX;\n        rgbw.brightness = white_value;\n        rgbw.isWhiteSelected = true;\n        ws2812fx.setMode(FX_MODE_STATIC);\n        ws2812fx.setColor(0, 0, 0); \n        newStateToPublish = true;\n      }\n    }\n\n    // check if the payload contains a new effect value\n    if (root.containsKey(\"effect\")) {\n      const char* effect = root[\"effect\"];\n\n      // TODO check if current effect is different\n      rgbw.white = PWM_MIN;\n      rgbw.isWhiteSelected = false;\n      newStateToPublish = true;\n\n      if (strcmp_P(effect, (const char*)name_0) == 0) {\n        ws2812fx.setMode(FX_MODE_STATIC);\n      } else if (strcmp_P(effect, (const char*)name_1) == 0) {\n        ws2812fx.setMode(FX_MODE_BLINK);\n      } else if (strcmp_P(effect, (const char*)name_2) == 0) {\n        ws2812fx.setMode(FX_MODE_BREATH);\n      } else if (strcmp_P(effect, (const char*)name_8) == 0) {\n        ws2812fx.setMode(FX_MODE_RANDOM_COLOR);\n      } else if (strcmp_P(effect, (const char*)name_11) == 0) {\n        ws2812fx.setMode(FX_MODE_RAINBOW);\n      } else if (strcmp_P(effect, (const char*)name_15) == 0) {\n        ws2812fx.setMode(FX_MODE_FADE);\n      } else if (strcmp_P(effect, (const char*)name_26) == 0) {\n        ws2812fx.setMode(FX_MODE_STROBE);\n      } else if (strcmp_P(effect, (const char*)name_27) == 0) {\n        ws2812fx.setMode(FX_MODE_STROBE_RAINBOW);\n      } else if (strcmp_P(effect, (const char*)name_28) == 0) {\n        ws2812fx.setMode(FX_MODE_MULTI_STROBE);\n      } else if (strcmp_P(effect, (const char*)name_29) == 0) {\n        ws2812fx.setMode(FX_MODE_BLINK_RAINBOW);\n      } else if (strcmp_P(effect, (const char*)name_44) == 0) {\n        ws2812fx.setMode(FX_MODE_COMET);\n      } else if (strcmp_P(effect, (const char*)name_48) == 0) {\n        ws2812fx.setMode(FX_MODE_FIRE_FLICKER);\n      } else if (strcmp_P(effect, (const char*)name_52) == 0) {\n        ws2812fx.setMode(FX_MODE_HALLOWEEN);\n      } else {\n        ws2812fx.setMode(FX_MODE_BLINK);\n      }   \n    }\n  }\n}\n\nvoid sendState(void) {\n  DynamicJsonBuffer dynamicJsonBuffer;\n  JsonObject& root = dynamicJsonBuffer.createObject();\n  root[\"state\"] = ws2812fx.isRunning() ? MQTT_STATE_ON_PAYLOAD : MQTT_STATE_OFF_PAYLOAD;\n  root[\"brightness\"] = rgbw.brightness;\n  JsonObject& color = root.createNestedObject(\"color\");\n  color[\"r\"] = rgbw.red;\n  color[\"g\"] = rgbw.green;\n  color[\"b\"] = rgbw.blue;\n  root[\"white_value\"] = rgbw.white == 0 ? 0 : rgbw.brightness;\n  root[\"effect\"] = ws2812fx.getModeName(ws2812fx.getMode());//\"Static\";\n\n  char tmp[128] = {0};\n  root.printTo(tmp);\n  mqttClient.publish(MQTT_STATE_TOPIC, tmp);\n}\n\nbool reconnect() {\n  if (mqttClient.connect(DEVICE_NAME, MQTT_USERNAME, MQTT_PASSWORD, MQTT_AVAILABILITY_TOPIC, 0, 1, MQTT_NOT_AVAILABLE_PAYLOAD)) {\n    mqttClient.subscribe(MQTT_CMD_TOPIC);\n    mqttClient.publish(MQTT_AVAILABILITY_TOPIC, MQTT_AVAILABLE_PAYLOAD);\n\n    sendState();\n  }\n  return mqttClient.connected();\n}\n\nvoid setupMQTT(void) {\n  mqttClient.setServer(MQTT_SERVER, MQTT_SERVER_PORT);\n  mqttClient.setCallback(callback);\n}\n\n///////////////////////////////////////////////////////////////////////////////////////////////\n// WIFI\n///////////////////////////////////////////////////////////////////////////////////////////////\n\nvoid setupWiFi(void) {\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n  \n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////////////////////////\n// SETUP and LOOP\n///////////////////////////////////////////////////////////////////////////////////////////////\n\nvoid setup() {\n  setupWiFi();\n\n  setupMQTT();\n\n  setupLight();\n  \n  ArduinoOTA.begin();\n}\n\n\nvoid loop() {\n  if (!mqttClient.connected()) {\n    long now = millis();\n    if (now - lastReconnectAttempt > 5000) {\n      lastReconnectAttempt = now;\n      if (reconnect())\n        lastReconnectAttempt = 0;\n    }\n  } else {\n    mqttClient.loop();\n  }\n  \n  ws2812fx.service();\n  \n  yield();\n\n  if (newStateToPublish) {\n    newStateToPublish = false;\n    sendState();  \n  }\n\n  yield();\n  \n  ArduinoOTA.handle();\n}\n"
  },
  {
    "path": "ha_mqtt_light_with_WiFiManager_mDNS_and_OTA/README.md",
    "content": "# MQTT Light with WiFiManager, mDNS and OTA - Home Assistant\nA simple example to control the built-in led connected to a NodeMCU board (ESP8266).\n\n## Advanced features\n- WiFiManager: To list the available Wifi AP and to connect to one of them.\n- mDNS:        To look for the IP address and the port of the local MQTT broker.\n- OTA:         To update the firmware over-the-air.\n\n## Configuration\n### MQTT broker server\nSteps:\n- sudo apt-get install avahi-deamon (installed by default)\n- sudo nano /etc/avahi/services/mqtt.service\n- Copy/paste the following lines:\n```xml\n<?xml version=\"1.0\" standalone='no'?>\n<!DOCTYPE service-group SYSTEM \"avahi-service.dtd\">\n<service-group>\n    <name replace-wildcards=\"yes\">%h</name>\n    <service>\n        <type>_mqtt._tcp</type>\n        <port>1883</port>\n    </service>\n</service-group>\n```\n- sudo service avahi-daemon restart\n\n### Home-Assistant\nWarning: 'F90D5F' corresponds to the chip ID of my ESP8266.\nYour chip ID is visible in the logs and corresponds to the name of the initial AP.\n\nconfiguration.yaml :\n```yaml\nlight:\n  platform: mqtt\n  name: 'Office light'\n  state_topic: '9A6C95/light'\n  command_topic: '9A6C95/light/switch'\n  optimistic: false\n```\n\n## Steps\n1. Select the Wifi AP provided by the ESP8266. A window is open,\n2. Select \"Configure WiFi\",\n3. Choose your Wifi AP in the list and enter your password,\n4. Enter the MQTT username and password. Press \"save\",\n5. Configure Home-Assitant.\n\n![Schematic](Schematic.jpg)\n\n"
  },
  {
    "path": "ha_mqtt_light_with_WiFiManager_mDNS_and_OTA/ha_mqtt_light_with_WiFiManager_mDNS_and_OTA.ino",
    "content": "/*\n  MQTT Light for Home-Assistant - NodeMCU (ESP8266)\n  https://home-assistant.io/components/switch.mqtt/\n\n  Features:\n    - WiFiManager\n    - mDNS\n    - OTA\n\n  Libraries:\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - WiFiManager: https://github.com/tzapu/WiFiManager\n    - ESP8266mDNS: https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266mDNS\n    - ArduinoJson: https://github.com/bblanchon/ArduinoJson\n\n  Sources:\n    - File > Examples > WiFiManager > AutoConnectWithFSParameters\n    - File > Examples > ArduinoOTA > BasicOTA\n\n  Configuration (HA):\n  Warning: 'F90D5F' corresponds to the chip ID of my ESP\n  Your chip ID is visible in the logs and the initial WIFI AP has the same name\n    light:\n      platform: mqtt\n      name: 'Office light'\n      state_topic: 'F90D5F/light'\n      command_topic: 'F90D5F/light/switch'\n      optimistic: false\n\n  Samuel M. - v1.0 - 08.2016\n  If you like this example, please add a star! Thank you!\n  https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n\n/*\n  WiFiManager\n  Doc: https://github.com/tzapu/WiFiManager\n  Moves the ESP8266 into AP mode and spins up a DNS and WebServer, IP 192.168.4.1\n  Scans the available AP, asks the password for the wished AP and tries to connect to it\n  Custom parameters:\n    - MQTT username\n    - MQTT password\n  How-to:\n    - Define #WIFI_MANAGER, or\n    - Set manually the variables, lines 72-75\n*/\n#define WIFI_MANAGER\n\n#ifdef WIFI_MANAGER\n  #include <DNSServer.h>\n  #include <ESP8266WebServer.h>\n  #include <WiFiManager.h>\n  #include <ArduinoJson.h>\n  #include <FS.h>\n  \n  // Wifi AP: SSID: chip ID, passowrd: WIFI_PASSWORD\n  const char              WIFI_PASSWORD[]           = \"password\";\n  char                    MQTT_USERNAME[10]         = {0};\n  char                    MQTT_PASSWORD[10]         = {0};\n  \n  // flag for saving data\n  bool                    m_shouldSaveConfig        = false;\n  \n  void saveConfigCallback () {\n    Serial.println(F(\"INFO: Should save config\"));\n    m_shouldSaveConfig = true;\n  }\n#else\n  const PROGMEM char*     WIFI_SSID                 = \"[Redacted]\";\n  const PROGMEM char*     WIFI_PASSWORD             = \"[Redacted]\";\n  const PROGMEM char*     MQTT_USERNAME             = \"[Redacted]\";\n  const PROGMEM char*     MQTT_PASSWORD             = \"[Redacted]\";\n#endif\n\n/*\n  DNS-SD - http://www.dns-sd.org\n  Soft: Avahi (Linux) or Bonjour (OS X/Windows)\n  Doc:  http://linux.die.net/man/5/avahi.service\n  Create a service on your machine, which hosts the MQTT broker\n  On Linux:\n    - sudo apt-get install avahi-deamon (installed by default)\n    - sudo nano /etc/avahi/services/mqtt.service\n    - Copy/paste the following lines:\n        <?xml version=\"1.0\" standalone='no'?>\n        <!DOCTYPE service-group SYSTEM \"avahi-service.dtd\">\n        <service-group>\n          <name replace-wildcards=\"yes\">%h</name>\n          <service>\n            <type>_mqtt._tcp</type>\n            <port>1883</port>\n          </service>\n        </service-group>\n    - sudo service avahi-daemon restart\n  How-to:\n    - Define #MDNS_SD, or\n    - Set manually the variables, lines 106-107\n*/\n#define MDNS_SD\n\n#ifdef MDNS_SD\n#include <ESP8266mDNS.h>\n#else\nconst PROGMEM char*     MQTT_SERVER_IP            = \"[Redacted]\";\nconst PROGMEM uint16_t  MQTT_SERVER_PORT          = 1883;\n#endif\n\n/*\n  OTA\n  Password: \"1234\" (line 341)\n*/\n\n#define OTA\n#ifdef OTA\n  #include <ESP8266mDNS.h>\n  #include <WiFiUdp.h>\n  #include <ArduinoOTA.h>\n#endif\n\n// MQTT\n#define MQTT_VERSION MQTT_VERSION_3_1_1\nchar                    MQTT_CLIENT_ID[6]         = {0};\n\n// topics: status:  <MQTT_CLIENT_ID>/light\n//         command: <MQTT_CLIENT_ID>/light/switch\nchar                    MQTT_LIGHT_STATUS_TOPIC[13]   = {0};\nchar                    MQTT_LIGHT_COMMAND_TOPIC[20]  = {0};\n\n// default payload\nconst char*             LIGHT_ON                  = \"ON\";\nconst char*             LIGHT_OFF                 = \"OFF\";\n\n// light is turned off by default\nboolean                 m_light_state             = false;\n\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\n\n// function called to publish the state of the light (on/off)\nvoid publishLightState() {\n  if (m_light_state) {\n    client.publish(MQTT_LIGHT_STATUS_TOPIC, LIGHT_ON, true);\n  } else {\n    client.publish(MQTT_LIGHT_STATUS_TOPIC, LIGHT_OFF, true);\n  }\n}\n\n// function called to turn on/off the light\nvoid setLightState() {\n  if (m_light_state) {\n    digitalWrite(BUILTIN_LED, LOW);\n    Serial.println(F(\"INFO: Light switched on...\"));\n  } else {\n    digitalWrite(BUILTIN_LED, HIGH);\n    Serial.println(F(\"INFO: Light switched off...\"));\n  }\n}\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n  // concat the payload into a string\n  String payload;\n  for (uint8_t i = 0; i < p_length; i++) {\n    payload.concat((char)p_payload[i]);\n  }\n\n  // handle message topic\n  if (String(MQTT_LIGHT_COMMAND_TOPIC).equals(p_topic)) {\n    // test if the payload is equal to \"ON\" or \"OFF\"\n    if (payload.equals(String(LIGHT_ON))) {\n      if (m_light_state != true) {\n        m_light_state = true;\n        setLightState();\n        publishLightState();\n      }\n    } else if (payload.equals(String(LIGHT_OFF))) {\n      if (m_light_state != false) {\n        m_light_state = false;\n        setLightState();\n        publishLightState();\n      }\n    }\n  }\n}\n\nvoid reconnect() {\n  while (!client.connected()) {\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {\n      Serial.println(F(\"INFO: Successfully connected to the MQTT broker\"));\n      publishLightState();\n      client.subscribe(MQTT_LIGHT_COMMAND_TOPIC);\n    } else {\n      Serial.print(F(\"ERROR: Failed to connect to the MQTT broker\"));\n      delay(5000);\n    }\n  }\n}\n\n\nvoid setup() {\n  Serial.begin(115200);\n\n  // init the built-in led\n  pinMode(BUILTIN_LED, OUTPUT);\n  setLightState();\n\n  // get the chip ID and concat this ID with the MQTT topics\n  sprintf(MQTT_CLIENT_ID, \"%06X\", ESP.getChipId());\n  sprintf(MQTT_LIGHT_STATUS_TOPIC, \"%s%s\", MQTT_CLIENT_ID, \"/light\");\n  sprintf(MQTT_LIGHT_COMMAND_TOPIC, \"%s%s\", MQTT_CLIENT_ID, \"/light/switch\");\n\n  Serial.print(F(\"MQTT id:\\t\\t \"));\n  Serial.println(MQTT_CLIENT_ID);\n\n  Serial.print(F(\"MQTT status topic:\\t \"));\n  Serial.println(MQTT_LIGHT_STATUS_TOPIC);\n\n  Serial.print(F(\"MQTT command topic:\\t \"));\n  Serial.println(MQTT_LIGHT_COMMAND_TOPIC);\n\n#ifdef WIFI_MANAGER\n  // clean FS, for testing\n  SPIFFS.format();\n\n  // read configuration from FS json\n  Serial.println(F(\"INFO: mounting FS...\"));\n\n  if (SPIFFS.begin()) {\n    Serial.println(F(\"INFO: mounted file system\"));\n    if (SPIFFS.exists(\"/config.json\")) {\n      Serial.println(F(\"INFO: reading config file\"));\n      File configFile = SPIFFS.open(\"/config.json\", \"r\");\n      if (configFile) {\n        Serial.println(F(\"INFO: opened config file\"));\n        size_t size = configFile.size();\n        // Allocate a buffer to store contents of the file.\n        std::unique_ptr<char[]> buf(new char[size]);\n\n        configFile.readBytes(buf.get(), size);\n        DynamicJsonBuffer jsonBuffer;\n        JsonObject& json = jsonBuffer.parseObject(buf.get());\n        json.printTo(Serial);\n        if (json.success()) {\n          Serial.println(F(\"\\nINFO: parsed json\"));\n          strcpy(MQTT_USERNAME, json[\"mqtt_username\"]);\n          strcpy(MQTT_PASSWORD, json[\"mqtt_password\"]);\n        } else {\n          Serial.println(F(\"ERROR: failed to load json config\"));\n        }\n      }\n    }\n  } else {\n    Serial.println(F(\"ERROR: failed to mount FS\"));\n  }\n\n  WiFiManagerParameter custom_mqtt_username(\"mqtt_username\", \"MQTT username\", MQTT_USERNAME, 15);\n  WiFiManagerParameter custom_mqtt_password(\"mqtt_password\", \"MQTT password\", MQTT_PASSWORD, 15, \"type=\\\"password\\\"\");\n\n  // WiFiManager, local intialization\n  WiFiManager wifiManager;\n\n  // set config save notify callback\n  wifiManager.setSaveConfigCallback(saveConfigCallback);\n\n  // add all the parameters\n  wifiManager.addParameter(&custom_mqtt_username);\n  wifiManager.addParameter(&custom_mqtt_password);\n\n  // reset settings, for testing\n  wifiManager.resetSettings();\n\n  // disable the debug output\n  wifiManager.setDebugOutput(false);\n\n  // fetches ssid and pass and tries to connect\n  // if it does not connect it starts an access point with the specified name\n  if (!wifiManager.autoConnect(MQTT_CLIENT_ID, WIFI_PASSWORD)) {\n    Serial.println(F(\"Error: Failed to connect and hit timeout\"));\n    delay(3000);\n    ESP.reset();\n    delay(5000);\n  }\n\n  // if you get here you have connected to the WiFi\n  Serial.println(F(\"INFO: Successfully connected to the Wifi AP\"));\n\n  // read updated parameters\n  strcpy(MQTT_USERNAME, custom_mqtt_username.getValue());\n  strcpy(MQTT_PASSWORD, custom_mqtt_password.getValue());\n\n  // save the custom parameters to FS\n  if (m_shouldSaveConfig) {\n    Serial.println(F(\"INFO: saving config\"));\n    DynamicJsonBuffer jsonBuffer;\n    JsonObject& json = jsonBuffer.createObject();\n    json[\"mqtt_username\"] = MQTT_USERNAME;\n    json[\"mqtt_password\"] = MQTT_PASSWORD;\n\n    File configFile = SPIFFS.open(\"/config.json\", \"w\");\n    if (!configFile) {\n      Serial.println(F(\"ERROR: failed to open config file for writing\"));\n    }\n    json.printTo(Serial);\n    json.printTo(configFile);\n    Serial.println();\n    configFile.close();\n  }\n\n  Serial.print(F(\"INFO: MQTT username: \"));\n  Serial.println(MQTT_USERNAME);\n\n  Serial.print(F(\"INFO: MQTT password: \"));\n  Serial.println(MQTT_PASSWORD);\n\n  Serial.print(F(\"INFO: Local IP address: \"));\n  Serial.println(WiFi.localIP());\n#else\n  WiFi.hostname(MQTT_CLIENT_ID);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(250);\n  }\n  Serial.println(F(\"INFO: Successfully connected to the Wifi AP\"));\n  Serial.print(F(\"INFO: Local IP address: \"));\n  Serial.println(WiFi.localIP());\n#endif\n\n  delay(500);\n\n#ifdef OTA\n  // set port to 8266\n  //ArduinoOTA.setPort(8266);\n\n  // set hostname\n  sprintf(MQTT_CLIENT_ID, \"%06X\", ESP.getChipId());\n  ArduinoOTA.setHostname(MQTT_CLIENT_ID);\n\n  // set a password\n  ArduinoOTA.setPassword((const char *)\"1234\");\n\n  ArduinoOTA.onStart([]() {\n    Serial.println(F(\"INFO: Start OTA\"));\n  });\n  ArduinoOTA.onEnd([]() {\n    Serial.println(F(\"INFO: End OTA\"));\n    ESP.reset();\n  });\n  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {\n    Serial.printf(\"INFO: Progress: %u%%\\r\", (progress / (total / 100)));\n  });\n  ArduinoOTA.onError([](ota_error_t error) {\n    Serial.printf(\"Error[%u]: \", error);\n    if (error == OTA_AUTH_ERROR) Serial.println(F(\"ERROR: OTA auth Failed\"));\n    else if (error == OTA_BEGIN_ERROR) Serial.println(F(\"ERROR: OTA begin Failed\"));\n    else if (error == OTA_CONNECT_ERROR) Serial.println(F(\"ERROR: OTA connect Failed\"));\n    else if (error == OTA_RECEIVE_ERROR) Serial.println(F(\"ERROR: OTA receive Failed\"));\n    else if (error == OTA_END_ERROR) Serial.println(F(\"ERROR: OTA end Failed\"));\n  });\n  ArduinoOTA.begin();\n#endif\n\n  delay(500);\n\n#ifdef MDNS_SD\n  if (!MDNS.begin(MQTT_CLIENT_ID)) {\n    Serial.println(F(\"ERROR: Setting up MDNS responder!\"));\n  }\n  Serial.println(F(\"INFO: mDNS responder started\"));\n  Serial.println(F(\"INFO: Sending mDNS query\"));\n  int n = MDNS.queryService(\"mqtt\", \"tcp\"); // Send out query for the MQTT service\n  Serial.println(F(\"INFO: mDNS query done\"));\n  if (n == 0) {\n    Serial.println(F(\"ERROR: No services found\"));\n  } else if (n > 1) {\n    Serial.println(F(\"ERROR: Multiple services found, remove the unnecessary mDNS services\"));\n  } else {\n    Serial.print(F(\"INFO: MQTT broker IP address: \"));\n    Serial.print(MDNS.IP(0));\n    Serial.print(F(\":\"));\n    Serial.println(MDNS.port(0));\n    client.setServer(MDNS.IP(0), int(MDNS.port(0)));\n  }\n#else\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n#endif\n\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  // put your main code here, to run repeatedly\n\n  // MQTT\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n\n  ArduinoOTA.handle();\n}\n"
  },
  {
    "path": "ha_mqtt_light_with_brightness/README.md",
    "content": "# MQTT Light with brightness support - Home Assistant\nA simple example to control a led connected to a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nlight:\n  - platform: mqtt\n    name: 'Office light'\n    state_topic: 'office/light'\n    command_topic: 'office/light/switch'\n    brightness_state_topic: 'office/light/brightness'\n    brightness_command_topic: 'office/light/brightness/set'\n    optimistic: false\n```\n\n## Schematic\n- GND - Resistor 220 Ohms - LED leg 1\n- D1/GPIO5 - LED leg 2 (longuest one)\n\n![Schematic](Schematic.png)\n"
  },
  {
    "path": "ha_mqtt_light_with_brightness/ha_mqtt_light_with_brightness.ino",
    "content": "/*\n   MQTT Light (with brightness) for Home-Assistant - NodeMCU (ESP8266)\n   https://home-assistant.io/components/light.mqtt/\n\n   Libraries :\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n\n   Schematic :\n    - https://github.com/mertenats/open-home-automation/blob/master/ha_mqtt_rgb_light/Schematic.png\n    - GND - Resistor 220 Ohms - LED leg 1\n    - D1/GPIO5 - LED leg 2 (longuest one)\n\n   Configuration (HA) : \n    light:\n      platform: mqtt\n      name: 'Office light'\n      state_topic: 'office/light'\n      command_topic: 'office/light/switch'\n      brightness_state_topic: 'office/light/brightness'\n      brightness_command_topic: 'office/light/brightness/set'\n      optimistic: false\n\n   Samuel M. - v1.0 - 08.2016\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wifi: SSID and password\nconst char*             WIFI_SSID         = \"[Redacted]\";\nconst char*             WIFI_PASSWORD     = \"[Redacted]\";\n\n// MQTT: ID, server IP, port, username and password\nconst PROGMEM char*     MQTT_CLIENT_ID    = \"office_light\";\nconst PROGMEM char*     MQTT_SERVER_IP    = \"[Redacted]\";\nconst PROGMEM uint16_t  MQTT_SERVER_PORT  = 1883;\nconst PROGMEM char*     MQTT_USER         = \"[Redacted]\";\nconst PROGMEM char*     MQTT_PASSWORD     = \"[Redacted]\";\n\n// MQTT: topics\n// state\nconst PROGMEM char*     MQTT_LIGHT_STATE_TOPIC                = \"office/light\";\nconst PROGMEM char*     MQTT_LIGHT_COMMAND_TOPIC              = \"office/light/switch\";\n\n// brightness\nconst PROGMEM char*     MQTT_LIGHT_BRIGHTNESS_STATE_TOPIC     = \"office/light/brightness\";\nconst PROGMEM char*     MQTT_LIGHT_BRIGHTNESS_COMMAND_TOPIC   = \"office/light/brightness/set\";\n\n// payloads by default (on/off)\nconst PROGMEM char*     LIGHT_ON          = \"ON\";\nconst PROGMEM char*     LIGHT_OFF         = \"OFF\";\n\n// variables used to store the statea and the brightness of the light\nboolean   m_light_state       = false;\nuint8_t   m_light_brightness  = 255;\n\n// pin used for the led (PWM)\nconst PROGMEM uint8_t LIGHT_PIN = 4;\n\n// buffer used to send/receive data with MQTT\nconst uint8_t MSG_BUFFER_SIZE = 20;\nchar m_msg_buffer[MSG_BUFFER_SIZE]; \n\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\n\n// function called to adapt the brightness and the state of the led\nvoid setLightState() {\n  if (m_light_state) {\n    analogWrite(LIGHT_PIN, m_light_brightness);\n    Serial.print(\"INFO: Brightness: \");\n    Serial.println(m_light_brightness);\n  } else {\n    analogWrite(LIGHT_PIN, 0);\n    Serial.println(\"INFO: Turn light off\");\n  }\n}\n\n// function called to publish the state of the led (on/off)\nvoid publishLightState() {\n  if (m_light_state) {\n    client.publish(MQTT_LIGHT_STATE_TOPIC, LIGHT_ON, true);\n  } else {\n    client.publish(MQTT_LIGHT_STATE_TOPIC, LIGHT_OFF, true);\n  }\n}\n\n// function called to publish the brightness of the led\nvoid publishLightBrightness() {\n  snprintf(m_msg_buffer, MSG_BUFFER_SIZE, \"%d\", m_light_brightness);\n  client.publish(MQTT_LIGHT_BRIGHTNESS_STATE_TOPIC, m_msg_buffer, true);\n}\n\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n  // concat the payload into a string\n  String payload;\n  for (uint8_t i = 0; i < p_length; i++) {\n    payload.concat((char)p_payload[i]);\n  }\n  // handle message topic\n  if (String(MQTT_LIGHT_COMMAND_TOPIC).equals(p_topic)) {\n    // test if the payload is equal to \"ON\" or \"OFF\"\n    if (payload.equals(String(LIGHT_ON))) {\n      if (m_light_state != true) {\n        m_light_state = true;\n        setLightState();\n        publishLightState();\n      }\n    } else if (payload.equals(String(LIGHT_OFF))) {\n      if (m_light_state != false) {\n        m_light_state = false;\n        setLightState();\n        publishLightState();\n      }\n    }\n  } else if (String(MQTT_LIGHT_BRIGHTNESS_COMMAND_TOPIC).equals(p_topic)) {\n    uint8_t brightness = payload.toInt();\n    if (brightness < 0 || brightness > 255) {\n      // do nothing...\n      return;\n    } else {\n      m_light_brightness = brightness;\n      setLightState();\n      publishLightBrightness();\n    }\n  }\n}\n\nvoid reconnect() {\n  // Loop until we're reconnected\n  while (!client.connected()) {\n    Serial.println(\"INFO: Attempting MQTT connection...\");\n    // Attempt to connect\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {\n      Serial.println(\"\\nINFO: connected\");\n      \n      // Once connected, publish an announcement...\n      // publish the initial values\n      publishLightState();\n      publishLightBrightness();\n\n      // ... and resubscribe\n      client.subscribe(MQTT_LIGHT_COMMAND_TOPIC);\n      client.subscribe(MQTT_LIGHT_BRIGHTNESS_COMMAND_TOPIC);\n    } else {\n      Serial.print(\"ERROR: failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\"DEBUG: try again in 5 seconds\");\n      // Wait 5 seconds before retrying\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  // init the serial\n  Serial.begin(115200);\n\n  // init the led\n  pinMode(LIGHT_PIN, OUTPUT);\n  analogWriteRange(255);\n  setLightState();\n\n  // init the WiFi connection\n  Serial.println();\n  Serial.println();\n  Serial.print(\"INFO: Connecting to \");\n  WiFi.mode(WIFI_STA);\n  Serial.println(WIFI_SSID);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n\n  Serial.println(\"\");\n  Serial.println(\"INFO: WiFi connected\");\n  Serial.print(\"INFO: IP address: \");\n  Serial.println(WiFi.localIP());\n\n  // init the MQTT connection\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n}\n"
  },
  {
    "path": "ha_mqtt_multisensor/Configuration/example.binary_sensor.yaml",
    "content": "# Example configuration.yaml entry\nbinary_sensor:\n  - platform: mqtt\n    name: 'Motion'\n    state_topic: '<CHIP_ID>/sensor/motion'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n    device_class: motion\n  - platform: mqtt\n    name: 'Door'\n    state_topic: '<CHIP_ID>/sensor/door'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n    device_class: opening\n  - platform: mqtt\n    name: 'Button'\n    state_topic: '<CHIP_ID>/sensor/button'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n"
  },
  {
    "path": "ha_mqtt_multisensor/Configuration/example.group.yaml",
    "content": "group:\n  multisensor:\n    name: 'Multisensor'\n    entities:\n      - sensor.temperature\n      - sensor.humidity\n      - sensor.luminosity\n      - binary_sensor.motion\n      - binary_sensor.door\n      - binary_sensor.button\n"
  },
  {
    "path": "ha_mqtt_multisensor/Configuration/example.sensor.yaml",
    "content": "# Example configuration.yml entry\nsensor:\n  - platform: mqtt\n    name: 'Temperature'\n    state_topic: '<CHIP_ID>/sensor/temperature'\n    unit_of_measurement: '°C'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n  - platform: mqtt\n    name: 'Humidity'\n    state_topic: '<CHIP_ID>/sensor/humidity'\n    unit_of_measurement: '%'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n  - platform: mqtt\n    name: 'Luminosity'\n    state_topic: '<CHIP_ID>/sensor/lux'\n    unit_of_measurement: 'lux'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n"
  },
  {
    "path": "ha_mqtt_multisensor/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Samuel Mertenat\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "ha_mqtt_multisensor/MultiSensor.cpp",
    "content": "#include \"Arduino.h\"\n#include \"MultiSensor.h\"\n\n#if defined(DHT_SENSOR)\n// https://github.com/adafruit/Adafruit_Sensor\n// https://github.com/adafruit/DHT-sensor-library\n#include \"DHT.h\"\n#define DHTTYPE DHT22\nDHT dht(DHT_PIN, DHTTYPE);\n#endif\n\n#if defined(SHT_SENSOR)\n// https://github.com/Sensirion/arduino-sht\n#include <Wire.h>\n#include \"SHTSensor.h\"\nSHTSensor sht;\n#endif\n\nvolatile uint8_t evt = NO_SENSOR_EVT;    \n\n///////////////////////////////////////////////////////////////////////////\n//  ISRs\n///////////////////////////////////////////////////////////////////////////\n\n#if defined(DOOR_SENSOR)\nvoid doorSensorISR(void) {\n  evt = DOOR_SENSOR_EVT;\n}\n#endif\n\n#if defined(MOTION_SENSOR)\nvoid motionSensorISR(void) {\n  evt = MOTION_SENSOR_EVT;\n}\n#endif\n\n#if defined(BUTTON_SENSOR)\nvoid buttonSensorISR(void) {\n  static unsigned long lastButtonSensorInterrupt = 0;\n  unsigned long currentButtonSensorInterrupt = millis();\n  if (currentButtonSensorInterrupt - lastButtonSensorInterrupt > 500)\n    evt = BUTTON_SENSOR_EVT;\n  lastButtonSensorInterrupt = currentButtonSensorInterrupt;\n}\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////\n//  Constructor, init(), handleEvt() & loop()\n///////////////////////////////////////////////////////////////////////////\nMultiSensor::MultiSensor(void) {}\n\nvoid MultiSensor::init(void) {\n#if defined(DOOR_SENSOR)\n  pinMode(DOOR_SENSOR, INPUT_PULLUP);\n  attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), doorSensorISR, CHANGE);\n  this->_doorState = this->_readDoorState();\n#endif\n#if defined(MOTION_SENSOR)\n  pinMode(MOTION_SENSOR_PIN, INPUT_PULLUP);\n  attachInterrupt(digitalPinToInterrupt(MOTION_SENSOR_PIN), motionSensorISR, CHANGE);\n  this->_motionState = digitalRead(MOTION_SENSOR_PIN);\n#endif\n#if defined(LDR_SENSOR)\n  pinMode(LDR_PIN, INPUT);\n  this->_ldrValue = analogRead(LDR_PIN);\n#endif\n#if defined(DHT_SENSOR)\n  dht.begin();\n  delay(2000);\n  this->_readDHTTemperature();\n  this->_readDHTHumidity();\n#endif\n#if defined(SHT_SENSOR)\n  Wire.begin(SHT_SCL_PIN, SHT_SDA_PIN);\n  sht.init();\n  sht.setAccuracy(SHTSensor::SHT_ACCURACY_MEDIUM); \n  this->_readSHTTemperature();\n  this->_readSHTHumidity();\n#endif\n#if defined(BUTTON_SENSOR)\n  pinMode(BUTTON_SENSOR, INPUT);\n  attachInterrupt(digitalPinToInterrupt(BUTTON_SENSOR), buttonSensorISR, CHANGE);\n#endif\n}\n\nvoid MultiSensor::handleEvt(void) {\n  switch(evt) {\n    case NO_SENSOR_EVT:\n      break;\n#if defined(DOOR_SENSOR)\n    case DOOR_SENSOR_EVT:\n      if (this->_readDoorState() != this->_doorState) {\n        this->_doorState = !this->_doorState;\n        this->_callback(DOOR_SENSOR_EVT);\n      }\n      evt = NO_SENSOR_EVT;\n      break;\n#endif\n#if defined(MOTION_SENSOR)\n    case MOTION_SENSOR_EVT:\n      if (digitalRead(MOTION_SENSOR_PIN) != this->_motionState) {\n        this->_motionState = !this->_motionState;\n        this->_callback(MOTION_SENSOR_EVT);\n      }\n      evt = NO_SENSOR_EVT;\n      break;\n#endif\n#if defined(BUTTON_SENSOR)\n    case BUTTON_SENSOR_EVT:\n      this->_buttonState = !this->_buttonState;\n      this->_callback(BUTTON_SENSOR_EVT);\n      evt = NO_SENSOR_EVT;\n      break;\n#endif\n#if defined(LDR_SENSOR)\n    case LDR_SENSOR_EVT:\n      this->_callback(LDR_SENSOR_EVT);\n      evt = NO_SENSOR_EVT;\n      break;\n#endif\n#if defined(DHT_SENSOR)\n    case DHT_TEMPERATURE_SENSOR_EVT:\n      this->_callback(DHT_TEMPERATURE_SENSOR_EVT);\n      evt = NO_SENSOR_EVT;\n      break;\n    case DHT_HUMIDITY_SENSOR_EVT:\n      this->_callback(DHT_HUMIDITY_SENSOR_EVT);\n      evt = NO_SENSOR_EVT;\n      break;\n#endif\n#if defined(SHT_SENSOR)\n    case SHT_TEMPERATURE_SENSOR_EVT:\n      this->_callback(SHT_TEMPERATURE_SENSOR_EVT);\n      evt = NO_SENSOR_EVT;\n      break;\n    case SHT_HUMIDITY_SENSOR_EVT:\n      this->_callback(SHT_HUMIDITY_SENSOR_EVT);\n      evt = NO_SENSOR_EVT;\n      break;\n#endif\n  }\n}\n\nvoid MultiSensor::loop(void) {\n  this->handleEvt();\n  \n#if defined(LDR_SENSOR)\n  static unsigned long lastLdrSensorMeasure = 0;\n  if (lastLdrSensorMeasure + LDR_MEASURE_INTERVAL <= millis()) {\n    lastLdrSensorMeasure = millis();\n    uint16_t currentLdrValue = analogRead(LDR_PIN);\n    if (currentLdrValue <= this->_ldrValue - LDR_OFFSET_VALUE || currentLdrValue >= this->_ldrValue + LDR_OFFSET_VALUE) {\n      this->_ldrValue = currentLdrValue;\n      evt = LDR_SENSOR_EVT;\n      return;\n    }\n  }\n#endif\n\n#if defined(DHT_SENSOR)\n  static unsigned long lastDHTTemperatureSensorMeasure = 0;\n  if (lastDHTTemperatureSensorMeasure + DHT_MEASURE_INTERVAL <= millis()) {\n    lastDHTTemperatureSensorMeasure = millis();\n    float currentDHTTemperature = this->_readDHTTemperature();\n    if (currentDHTTemperature <= this->_DHTTemperature - DHT_TEMPERATURE_OFFSET_VALUE || currentDHTTemperature >= this->_DHTTemperature + DHT_TEMPERATURE_OFFSET_VALUE) {\n      this->_DHTTemperature = currentDHTTemperature;\n      evt = DHT_TEMPERATURE_SENSOR_EVT;\n      return;\n    }\n  }\n  \n  static unsigned long lastDHTHumiditySensorMeasure = 0;\n  if (lastDHTHumiditySensorMeasure + DHT_MEASURE_INTERVAL <= millis()) {\n    lastDHTHumiditySensorMeasure = millis();\n    float currentDHTHumidity = this->_readDHTHumidity();\n    if (currentDHTHumidity <= this->_DHTHumidity - DHT_HUMIDITY_OFFSET_VALUE || currentDHTHumidity >= this->_DHTHumidity + DHT_HUMIDITY_OFFSET_VALUE) {\n      this->_DHTHumidity = currentDHTHumidity;\n      evt = DHT_HUMIDITY_SENSOR_EVT;\n      return;\n    }\n  }\n#endif\n#if defined(SHT_SENSOR)\n  static unsigned long lastSHTTemperatureSensorMeasure = 0;\n  if (lastSHTTemperatureSensorMeasure + SHT_MEASURE_INTERVAL <= millis()) {\n    lastSHTTemperatureSensorMeasure = millis();\n    float currentSHTTemperature = this->_readSHTTemperature();\n    if (currentSHTTemperature <= this->_SHTTemperature - SHT_TEMPERATURE_OFFSET_VALUE || currentSHTTemperature >= this->_SHTTemperature + SHT_TEMPERATURE_OFFSET_VALUE) {\n      this->_SHTTemperature = currentSHTTemperature;\n      evt = SHT_TEMPERATURE_SENSOR_EVT;\n      return;\n    }\n  }\n  \n  static unsigned long lastSHTHumiditySensorMeasure = 0;\n  if (lastSHTHumiditySensorMeasure + SHT_MEASURE_INTERVAL <= millis()) {\n    lastSHTHumiditySensorMeasure = millis();\n    float currentSHTHumidity = this->_readSHTHumidity();\n    if (currentSHTHumidity <= this->_SHTHumidity - SHT_HUMIDITY_OFFSET_VALUE || currentSHTHumidity >= this->_SHTHumidity + SHT_HUMIDITY_OFFSET_VALUE) {\n      this->_SHTHumidity = currentSHTHumidity;\n      evt = SHT_HUMIDITY_SENSOR_EVT;\n      return;\n    }\n  }\n#endif\n}\n\n\n///////////////////////////////////////////////////////////////////////////\n//  setCallback()\n///////////////////////////////////////////////////////////////////////////\nvoid MultiSensor::setCallback(void (*callback)(uint8_t)) {\n  this->_callback = callback;\n}\n\n\n///////////////////////////////////////////////////////////////////////////\n//  Getters \n///////////////////////////////////////////////////////////////////////////\n#if defined(DOOR_SENSOR)\nbool MultiSensor::_readDoorState(void) {\n  return digitalRead(DOOR_SENSOR);\n}\n\nbool MultiSensor::getDoorState(void) {\n  return this->_doorState;\n}\n#endif\n\n#if defined(MOTION_SENSOR)\nbool MultiSensor::getMotionState(void) {\n  return this->_motionState;\n}\n#endif\n\n#if defined(LDR_SENSOR)\nuint16_t MultiSensor::getLux(void) {\n  // http://forum.arduino.cc/index.php?topic=37555.0\n  // https://forum.arduino.cc/index.php?topic=185158.0\n  float volts = this->_ldrValue * REFERENCE_VOLTAGE / ADC_PRECISION;\n  float amps = volts / LDR_RESISTOR_VALUE;\n  float lux = amps * 1000000 * 2.0;\n  return uint16_t(lux);\n}\n#endif\n\n\n#if defined(DHT_SENSOR)\nfloat MultiSensor::_readDHTTemperature(void) {\n  float temperature = dht.readTemperature();\n\n  if (isnan(temperature)) {\n    return this->_DHTTemperature;\n  }\n  return temperature;\n}\n\nfloat MultiSensor::_readDHTHumidity(void) {\n  float humidity = dht.readHumidity();\n\n  if (isnan(humidity)) {\n    return this->_DHTHumidity;\n  }\n  return humidity;\n}\n\nfloat MultiSensor::getDHTTemperature(void) {\n  return this->_DHTTemperature;\n}\n\nfloat MultiSensor::getDHTHumidity(void) {\n  return this->_DHTHumidity;\n}\n#endif\n\n\n#if defined(SHT_SENSOR)\nfloat MultiSensor::_readSHTTemperature(void) {\n  float temperature = sht.getTemperature();\n  \n  if (isnan(temperature)) {\n    return this->_SHTTemperature;\n  }\n  return temperature;\n}\n\nfloat MultiSensor::_readSHTHumidity(void) {\n  float humidity = sht.getHumidity();\n\n  if (isnan(humidity)) {\n    return this->_SHTHumidity;\n  }\n  return humidity;\n}\n\nfloat MultiSensor::getSHTTemperature(void) {\n  return this->_SHTTemperature;\n}\n\nfloat MultiSensor::getSHTHumidity(void) {\n  return this->_SHTHumidity;\n}\n#endif\n\n\n#if defined(BUTTON_SENSOR)\nbool MultiSensor::getButtonState(void) {\n  return this->_buttonState;\n}\n#endif\n"
  },
  {
    "path": "ha_mqtt_multisensor/MultiSensor.h",
    "content": "#ifndef MultiSensor_h\n#define MultiSensor_h\n\n#include \"Arduino.h\"\n#include \"config.h\"\n\n#define NO_SENSOR_EVT                 0\n#if defined(DOOR_SENSOR)\n#define DOOR_SENSOR_EVT               1\n#endif\n#if defined(MOTION_SENSOR)\n#define MOTION_SENSOR_EVT             2\n#endif\n#if defined(LDR_SENSOR)\n#define LDR_SENSOR_EVT                3\n#endif\n#if defined(DHT_SENSOR)\n#define DHT_TEMPERATURE_SENSOR_EVT    4\n#define DHT_HUMIDITY_SENSOR_EVT       5\n#endif\n#if defined(SHT_SENSOR)\n#define SHT_TEMPERATURE_SENSOR_EVT    6\n#define SHT_HUMIDITY_SENSOR_EVT       7\n#endif\n#if defined(BUTTON_SENSOR)\n#define BUTTON_SENSOR_EVT             8\n#endif\n\nclass MultiSensor {\n  public:\n    MultiSensor(void);\n    void init(void);\n    void loop(void);\n    void setCallback(void (*callback)(uint8_t));\n    \n#if defined(DOOR_SENSOR)\n    bool getDoorState(void);\n#endif\n#if defined(MOTION_SENSOR)\n    bool getMotionState(void);\n#endif\n#if defined(LDR_SENSOR)\n    uint16_t getLux(void);\n#endif\n#if defined(DHT_SENSOR)\n    float getDHTTemperature(void);\n    float getDHTHumidity(void);\n#endif\n#if defined(SHT_SENSOR)\n    float getSHTTemperature(void);\n    float getSHTHumidity(void);\n#endif\n#if defined(BUTTON_SENSOR)\n    bool getButtonState(void);\n#endif\n  private:\n    void (*_callback)(uint8_t);\n    void handleEvt(void);\n#if defined(DOOR_SENSOR)\n    bool _readDoorState(void);\n    bool _doorState = false;\n#endif\n#if defined(MOTION_SENSOR)\n    bool _motionState = false;\n#endif\n#if defined(LDR_SENSOR)\n    uint16_t _ldrValue = 0;\n#endif\n#if defined(DHT_SENSOR)\n    float _readDHTTemperature(void);\n    float _readDHTHumidity(void);\n    float _DHTTemperature = 0;\n    float _DHTHumidity = 0;\n#endif\n#if defined(SHT_SENSOR)\n    float _readSHTTemperature(void);\n    float _readSHTHumidity(void);\n    float _SHTTemperature = 0;\n    float _SHTHumidity = 0;\n#endif\n#if defined(BUTTON_SENSOR)\n    bool _buttonState = false;\n#endif\n};\n#endif\n"
  },
  {
    "path": "ha_mqtt_multisensor/README.md",
    "content": "# MQTT - MultiSensor - Home Assistant\nA full example describing how to monitor your environment with an ESP8266, the MQTT protocol and Home Assistant.\n\n## Features\n- Temperature (DHT22, SHT3X)\n- Humidity (DHT22, SHT3X)\n- Luminosity (Photoresistor, TEMT6000)\n- Motion (AM312, RCWL 0516)\n- Door/Window state ON/OFF\n- Button state ON/OFF\n\n## Schematic\n### DHT22 sensor\nTemperature and Humidity sensor. Schematic available [here](https://github.com/mertenats/Open-Home-Automation/tree/master/ha_mqtt_sensor_dht22).\n\n- DHT22 leg 1 - VCC\n- DHT22 leg 2 - D2 - Resistor 4.7K Ohms - GND\n- DHT22 leg 4 - GND\n\n### SHT3X sensor\nTemperature and Humidity sensor.\n\n- SHT3X VCC - VCC\n- SHT3X GND - GND\n- SHT3X SCL - D2\n- SHT3X SDA - D3\n\n### Photoresistor\nLuminosity sensor. Schematic available [here](https://github.com/mertenats/Open-Home-Automation/tree/master/ha_mqtt_sensor_photocell).\n\n- Photocell leg 1 - VCC\n- Photocell leg 2 - A0 - Resistor 10K Ohms - GND\n\n### TEMT6000\nLuminosity sensor.\n\n- TEMT6000 VCC - VCC\n- TEMT6000 GND - GND\n- TEMT6000 OUT - A0\n\n### AM312 sensor\nMotion sensor. Schematic available [here](https://github.com/mertenats/Open-Home-Automation/tree/master/ha_mqtt_binary_sensor_pir).\n\n- PIR leg 1 - VCC\n- PIR leg 2 - D7\n- PIR leg 3 - GND\n\n### RCWL 0516 sensor\nMotion sensor.\n\n- RCWL 0516 3v3 - VCC\n- RCWL 0516 GND - GND\n- RCWL 0516 OUT - D7\n\n### Magnet\nDoor/Window state sensor. Schematic available [here](https://github.com/mertenats/Open-Home-Automation/tree/master/ha_mqtt_binary_sensor_door).\n\n- Door sensor leg 1 - D3\n- Door sensor leg 2 - GND\n\n### Button\nButton ON/OFF. Schematic available [here](https://github.com/mertenats/Open-Home-Automation/tree/master/ha_mqtt_switch).\n\n- Switch leg 1 - VCC\n- Switch leg 2 - D1 - Resistor 10K Ohms - GND\n\n![Schematic](Images/Schematic.jpg)\n\n## Configuration\nTo configure this sketch, you have to rename the header file `example.config.h` in `config.h`. Then, it is possible to enable/disable sensors in the `HARDWARE SECTION` or edit your Wi-Fi and MQTT credentials in the `SOFTWARE SECTION`.\n\n### Sensors\n```\n// Door sensor\n#define DOOR_SENSOR                     D3\n\n// Motion sensor\n#define MOTION_SENSOR                      D7\n\n// Photoresistor sensor\n#define LDR_SENSOR                      A0\n\n// Temperature and humidity sensor (DHT22)\n#define DHT_SENSOR                  D2\n\n// Button\n#define BUTTON_SENSOR                   D1\n```\n\n### Credentials\n```\n// Wi-Fi credentials\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n// MQTT\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n```\n\n### Home Assistant\nTo add the motion sensor, the door/window state sensor and the button to Home Assistant, please edit and add this snippet into your configuration.\n\n```yaml\n# Example configuration.yaml entry\nbinary_sensor:\n  - platform: mqtt\n    name: 'Motion'\n    state_topic: '<CHIP_ID>/sensor/motion'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n    device_class: motion\n  - platform: mqtt\n    name: 'Door'\n    state_topic: '<CHIP_ID>/sensor/door'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n    device_class: opening\n  - platform: mqtt\n    name: 'Button'\n    state_topic: '<CHIP_ID>/sensor/button'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n```\n\nTo add the temperature and humidity sensor and the luminosity sensor, please edit and add this snippet into your configuration.\n\n```yaml\n# Example configuration.yml entry\nsensor:\n  - platform: mqtt\n    name: 'Temperature'\n    state_topic: '<CHIP_ID>/sensor/temperature'\n    unit_of_measurement: '°C'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n  - platform: mqtt\n    name: 'Humidity'\n    state_topic: '<CHIP_ID>/sensor/humidity'\n    unit_of_measurement: '%'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n  - platform: mqtt\n    name: 'Luminosity'\n    state_topic: '<CHIP_ID>/sensor/lux'\n    unit_of_measurement: 'lux'\n    availability_topic: '<CHIP_ID>/status'\n    payload_available: 'online'\n    payload_not_available: 'offline'\n```\n\n## Licence\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  SOFTWARE.\n\n*If you like the content of this repo, please add a star! Thank you!*\n"
  },
  {
    "path": "ha_mqtt_multisensor/example.config .h",
    "content": "///////////////////////////////////////////////////////////////////////////\n//  CONFIGURATION - HARDWARE\n///////////////////////////////////////////////////////////////////////////\n// Door sensor\n#define DOOR_SENSOR                     D3\n#if defined(DOOR_SENSOR)\n#define DOOR_SENSOR_NAME                \"door\" // used for the MQTT topic\n#endif\n\n// Motion sensor\n//   - AM312\n//   - RCWL 0516\n#define MOTION_SENSOR\n#if defined(MOTION_SENSOR)\n#define MOTION_SENSOR_NAME                 \"motion\"\n#define MOTION_SENSOR_PIN                  D7\n#endif\n\n// Ambient light sensor\n//   - Photoresistor\n//   - TEMT6000 sensor\n// Do not add a 10 kOhms resistor if you're using the TEMT6000\n// sensor (already present on the PCB)\n//#define LDR_SENSOR   \n#define LDR_SENSOR\n#if defined(LDR_SENSOR)\n#define LDR_SENSOR_NAME                 \"lux\"\n#define LDR_OFFSET_VALUE                25\n#define LDR_MEASURE_INTERVAL            15000   // [ms]\n#define REFERENCE_VOLTAGE               3.3     // [v]\n#define ADC_PRECISION                   1024.0  // 10 bits\n#define LDR_RESISTOR_VALUE              10000.0  // [Ohms]\n#define LDR_PIN                         A0\n#endif\n\n// Temperature and humidity sensor (DHT22)\n//#define DHT_SENSOR\n#if defined(DHT_SENSOR)\n#define DHT_TEMPERATURE_SENSOR_NAME     \"temperature\"\n#define DHT_HUMIDITY_SENSOR_NAME        \"humidity\"\n#define DHT_TEMPERATURE_OFFSET_VALUE    0.2   // [°C]\n#define DHT_HUMIDITY_OFFSET_VALUE       0.5   // [%]\n#define DHT_MEASURE_INTERVAL            30000 // [ms]\n#define DHT_PIN                         D2\n#endif\n\n// Temperature and humidity sensor (Sensirion SHT3X)\n#define SHT_SENSOR\n#if defined(SHT_SENSOR)\n#define SHT_TEMPERATURE_SENSOR_NAME   \"temperature\"\n#define SHT_HUMIDITY_SENSOR_NAME      \"humidity\"\n#define SHT_TEMPERATURE_OFFSET_VALUE  0.2   // [°C]\n#define SHT_HUMIDITY_OFFSET_VALUE     0.5   // [%]\n#define SHT_MEASURE_INTERVAL          30000 // [ms]\n#define SHT_SDA_PIN                   D3\n#define SHT_SCL_PIN                   D2\n#endif\n\n// Button\n#define BUTTON_SENSOR                   D1\n#if defined(BUTTON_SENSOR)\n#define BUTTON_SENSOR_NAME              \"button\"\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////\n//  CONFIGURATION - SOFTWARE\n///////////////////////////////////////////////////////////////////////////\n// Debug output\n#define DEBUG_SERIAL\n\n// Wi-Fi credentials\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n// Over-the-Air update\n#define OTA\n#define OTA_HOSTNAME  \"MultiSensor\"  // hostname esp8266-[ChipID] by default\n//#define OTA_PASSWORD  \"password\"  // no password by default\n//#define OTA_PORT      8266        // port 8266 by default\n\n// MQTT\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n\n#define MQTT_CONNECTION_TIMEOUT 5000 // [ms]\n\n#define MQTT_AVAILABILITY_TOPIC_TEMPLATE  \"%s/status\" // MQTT availability: online/offline\n#define MQTT_SENSOR_TOPIC_TEMPLATE        \"%s/sensor/%s\"\n\n#define MQTT_PAYLOAD_ON   \"ON\"\n#define MQTT_PAYLOAD_OFF  \"OFF\"\n"
  },
  {
    "path": "ha_mqtt_multisensor/ha_mqtt_multisensor.ino",
    "content": "#include <ESP8266WiFi.h>\n#include \"MultiSensor.h\"\n#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient\n#if defined(OTA)\n#include <ArduinoOTA.h>\n#endif\n\n#if defined(DEBUG_SERIAL)\n#define     DEBUG_PRINT(x)    Serial.print(x)\n#define     DEBUG_PRINTLN(x)  Serial.println(x)\n#else\n#define     DEBUG_PRINT(x)\n#define     DEBUG_PRINTLN(x)\n#endif\n\nMultiSensor   ms;\nWiFiClient    wifiClient;\nPubSubClient  mqttClient(wifiClient);\n\n\n///////////////////////////////////////////////////////////////////////////\n//   WiFi\n///////////////////////////////////////////////////////////////////////////\n/*\n   Function called to handle WiFi events\n*/\nvoid handleWiFiEvent(WiFiEvent_t event) {\n  switch (event) {\n    case WIFI_EVENT_STAMODE_GOT_IP:\n      DEBUG_PRINTLN(F(\"INFO: Connection successful to the Wi-Fi AP\"));\n      DEBUG_PRINT(F(\"INFO: IP address: \"));\n      DEBUG_PRINTLN(WiFi.localIP());\n      break;\n    case WIFI_EVENT_STAMODE_DISCONNECTED:\n      DEBUG_PRINTLN(F(\"ERROR: Connection lost from the Wi-Fi AP\"));\n      /*\n         TODO: Doing something smarter than rebooting the device\n      */\n      delay(5000);\n      ESP.restart();\n      break;\n    default:\n      DEBUG_PRINT(F(\"INFO: WiFi event: \"));\n      DEBUG_PRINTLN(event);\n      break;\n  }\n}\n\n/*\n   Function called to setup the connection to the WiFi AP\n*/\nvoid setupWiFi() {\n  DEBUG_PRINT(F(\"INFO: WiFi connecting to: \"));\n  DEBUG_PRINTLN(WIFI_SSID);\n\n  delay(10);\n\n  WiFi.mode(WIFI_STA);\n  WiFi.onEvent(handleWiFiEvent);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  randomSeed(micros());\n}\n\n\n///////////////////////////////////////////////////////////////////////////\n//   OTA\n///////////////////////////////////////////////////////////////////////////\n#if defined(OTA)\n/*\n   Function called to setup OTA updates\n*/\nvoid setupOTA() {\n#if defined(OTA_HOSTNAME)\n  ArduinoOTA.setHostname(OTA_HOSTNAME);\n  DEBUG_PRINT(F(\"INFO: OTA hostname sets to: \"));\n  DEBUG_PRINTLN(OTA_HOSTNAME);\n#endif\n\n#if defined(OTA_PORT)\n  ArduinoOTA.setPort(OTA_PORT);\n  DEBUG_PRINT(F(\"INFO: OTA port sets to: \"));\n  DEBUG_PRINTLN(OTA_PORT);\n#endif\n\n#if defined(OTA_PASSWORD)\n  ArduinoOTA.setPassword((const char *)OTA_PASSWORD);\n  DEBUG_PRINT(F(\"INFO: OTA password sets to: \"));\n  DEBUG_PRINTLN(OTA_PASSWORD);\n#endif\n\n  ArduinoOTA.onStart([]() {\n    DEBUG_PRINTLN(F(\"INFO: OTA starts\"));\n  });\n  ArduinoOTA.onEnd([]() {\n    DEBUG_PRINTLN(F(\"INFO: OTA ends\"));\n  });\n  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {\n    DEBUG_PRINT(F(\"INFO: OTA progresses: \"));\n    DEBUG_PRINT(progress / (total / 100));\n    DEBUG_PRINTLN(F(\"%\"));\n  });\n  ArduinoOTA.onError([](ota_error_t error) {\n    DEBUG_PRINT(F(\"ERROR: OTA error: \"));\n    DEBUG_PRINTLN(error);\n    if (error == OTA_AUTH_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA auth failed\"));\n    else if (error == OTA_BEGIN_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA begin failed\"));\n    else if (error == OTA_CONNECT_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA connect failed\"));\n    else if (error == OTA_RECEIVE_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA receive failed\"));\n    else if (error == OTA_END_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA end failed\"));\n  });\n  ArduinoOTA.begin();\n}\n\n/*\n   Function called to handle OTA updates\n*/\nvoid handleOTA() {\n  ArduinoOTA.handle();\n}\n#endif\n\n\n\n///////////////////////////////////////////////////////////////////////////\n//   MQTT\n///////////////////////////////////////////////////////////////////////////\nvolatile unsigned long lastMQTTConnection = 0;\nchar MQTT_CLIENT_ID[7] = {0};\nchar MQTT_PAYLOAD[8] = {0};\nchar MQTT_AVAILABILITY_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_AVAILABILITY_TOPIC_TEMPLATE) - 2] = {0};\n#if defined(MOTION_SENSOR)\nchar MQTT_MOTION_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(MOTION_SENSOR_NAME) - 4] = {0};\n#endif\n#if defined(DOOR_SENSOR)\nchar MQTT_DOOR_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(DOOR_SENSOR_NAME) - 4] = {0};\n#endif\n#if defined(LDR_SENSOR)\nchar MQTT_LDR_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(LDR_SENSOR_NAME) - 4] = {0};\n#endif\n#if defined(DHT_SENSOR)\nchar MQTT_DHT_TEMPERATURE_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(DHT_TEMPERATURE_SENSOR_NAME) - 4] = {0};\nchar MQTT_DHT_HUMIDITY_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(DHT_HUMIDITY_SENSOR_NAME) - 4] = {0};\n#endif\n#if defined(SHT_SENSOR)\nchar MQTT_SHT_TEMPERATURE_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(SHT_TEMPERATURE_SENSOR_NAME) - 4] = {0};\nchar MQTT_SHT_HUMIDITY_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(SHT_HUMIDITY_SENSOR_NAME) - 4] = {0};\n#endif\n#if defined(BUTTON_SENSOR)\nchar MQTT_BUTTON_SENSOR_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_SENSOR_TOPIC_TEMPLATE) + sizeof(BUTTON_SENSOR_NAME) - 4] = {0};\n#endif\n/*\n  Function called to publish to a MQTT topic with the given payload\n*/\nvoid publishToMQTT(char* p_topic, char* p_payload) {\n  if (mqttClient.publish(p_topic, p_payload, true)) {\n    DEBUG_PRINT(F(\"INFO: MQTT message published successfully, topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\", payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  } else {\n    DEBUG_PRINTLN(F(\"ERROR: MQTT message not published, either connection lost, or message too large. Topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\" , payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  }\n}\n\n/*\n  Function called to connect/reconnect to the MQTT broker\n*/\nvoid connectToMQTT() {\n  if (!mqttClient.connected()) {\n    if (lastMQTTConnection < millis()) {\n      if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD, MQTT_AVAILABILITY_TOPIC, 0, 1, \"offline\")) {\n        DEBUG_PRINTLN(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n        publishToMQTT(MQTT_AVAILABILITY_TOPIC, \"online\");\n\n        // publish sensors' states\n#if defined(DOOR_SENSOR)\n        if (!ms.getDoorState()) {\n          publishToMQTT(MQTT_DOOR_SENSOR_TOPIC, MQTT_PAYLOAD_ON);\n        } else {\n          publishToMQTT(MQTT_DOOR_SENSOR_TOPIC, MQTT_PAYLOAD_OFF);\n        }\n#endif\n#if defined(MOTION_SENSOR)\n        if (ms.getMotionState()) {\n          publishToMQTT(MQTT_MOTION_SENSOR_TOPIC, MQTT_PAYLOAD_ON);\n        } else {\n          publishToMQTT(MQTT_MOTION_SENSOR_TOPIC, MQTT_PAYLOAD_OFF);\n        }\n#endif\n#if defined(LDR_SENSOR)\n        itoa (ms.getLux(), MQTT_PAYLOAD, 10);\n        publishToMQTT(MQTT_LDR_SENSOR_TOPIC, MQTT_PAYLOAD);\n#endif\n#if defined(DHT_SENSOR)\n        dtostrf(ms.getDHTTemperature(), 2, 2, MQTT_PAYLOAD);\n        publishToMQTT(MQTT_DHT_TEMPERATURE_SENSOR_TOPIC, MQTT_PAYLOAD);\n        dtostrf(ms.getDHTHumidity(), 2, 2, MQTT_PAYLOAD);\n        publishToMQTT(MQTT_DHT_HUMIDITY_SENSOR_TOPIC, MQTT_PAYLOAD);\n#endif\n#if defined(SHT_SENSOR)\n        dtostrf(ms.getSHTTemperature(), 2, 2, MQTT_PAYLOAD);\n        publishToMQTT(MQTT_SHT_TEMPERATURE_SENSOR_TOPIC, MQTT_PAYLOAD);\n        dtostrf(ms.getSHTHumidity(), 2, 2, MQTT_PAYLOAD);\n        publishToMQTT(MQTT_SHT_HUMIDITY_SENSOR_TOPIC, MQTT_PAYLOAD);\n#endif\n#if defined(BUTTON_SENSOR)\n        if (ms.getButtonState()) {\n          publishToMQTT(MQTT_BUTTON_SENSOR_TOPIC, MQTT_PAYLOAD_ON);\n        } else {\n          publishToMQTT(MQTT_BUTTON_SENSOR_TOPIC, MQTT_PAYLOAD_OFF);\n        }\n#endif\n      } else {\n        DEBUG_PRINTLN(F(\"ERROR: The connection to the MQTT broker failed\"));\n        DEBUG_PRINT(F(\"INFO: MQTT username: \"));\n        DEBUG_PRINTLN(MQTT_USERNAME);\n        DEBUG_PRINT(F(\"INFO: MQTT password: \"));\n        DEBUG_PRINTLN(MQTT_PASSWORD);\n        DEBUG_PRINT(F(\"INFO: MQTT broker: \"));\n        DEBUG_PRINTLN(MQTT_SERVER);\n      }\n      lastMQTTConnection = millis() + MQTT_CONNECTION_TIMEOUT;\n    }\n  }\n}\n\nvoid onMultiSensorEvent(uint8_t p_evt) {\n  DEBUG_PRINT(F(\"INFO: onMultiSensorEvent(): evt: \"));\n  DEBUG_PRINTLN(p_evt);\n  switch (p_evt) {\n#if defined(DOOR_SENSOR)\n    case DOOR_SENSOR_EVT:\n      if (ms.getDoorState()) {\n        // ON:  means that the door is opened (getDoorState() == 0)\n        // OFF: means that the door is closed\n        publishToMQTT(MQTT_DOOR_SENSOR_TOPIC, MQTT_PAYLOAD_OFF);\n      } else {\n        publishToMQTT(MQTT_DOOR_SENSOR_TOPIC, MQTT_PAYLOAD_ON);\n      }\n      break;\n#endif\n#if defined(MOTION_SENSOR)\n    case MOTION_SENSOR_EVT:\n      if (ms.getMotionState()) {\n        publishToMQTT(MQTT_MOTION_SENSOR_TOPIC, MQTT_PAYLOAD_ON);\n      } else {\n        publishToMQTT(MQTT_MOTION_SENSOR_TOPIC, MQTT_PAYLOAD_OFF);\n      }\n      break;\n#endif\n#if defined(LDR_SENSOR)\n    case LDR_SENSOR_EVT:\n      itoa (ms.getLux(), MQTT_PAYLOAD, 10);\n      publishToMQTT(MQTT_LDR_SENSOR_TOPIC, MQTT_PAYLOAD);\n      break;\n#endif\n#if defined(DHT_SENSOR)\n    case DHT_TEMPERATURE_SENSOR_EVT:\n      dtostrf(ms.getDHTTemperature(), 2, 2, MQTT_PAYLOAD);\n      publishToMQTT(MQTT_DHT_TEMPERATURE_SENSOR_TOPIC, MQTT_PAYLOAD);\n      break;\n    case DHT_HUMIDITY_SENSOR_EVT:\n      dtostrf(ms.getDHTHumidity(), 2, 2, MQTT_PAYLOAD);\n      publishToMQTT(MQTT_DHT_HUMIDITY_SENSOR_TOPIC, MQTT_PAYLOAD);\n      break;\n#endif\n#if defined(SHT_SENSOR)\n    case SHT_TEMPERATURE_SENSOR_EVT:\n      dtostrf(ms.getSHTTemperature(), 2, 2, MQTT_PAYLOAD);\n      publishToMQTT(MQTT_SHT_TEMPERATURE_SENSOR_TOPIC, MQTT_PAYLOAD);\n      break;\n    case SHT_HUMIDITY_SENSOR_EVT:\n      dtostrf(ms.getSHTHumidity(), 2, 2, MQTT_PAYLOAD);\n      publishToMQTT(MQTT_SHT_HUMIDITY_SENSOR_TOPIC, MQTT_PAYLOAD);\n      break;\n#endif\n#if defined(BUTTON_SENSOR)\n    case BUTTON_SENSOR_EVT:\n      if (ms.getButtonState()) {\n        publishToMQTT(MQTT_BUTTON_SENSOR_TOPIC, MQTT_PAYLOAD_ON);\n      } else {\n        publishToMQTT(MQTT_BUTTON_SENSOR_TOPIC, MQTT_PAYLOAD_OFF);\n      }\n      break;\n#endif\n  }\n}\n\nvoid setup() {\n#if defined(DEBUG_SERIAL)\n  Serial.begin(115200);\n#endif\n\n  setupWiFi();\n\n#if defined(OTA)\n  setupOTA();\n#endif\n\n  ms.init();\n  ms.setCallback(onMultiSensorEvent);\n  \n  sprintf(MQTT_CLIENT_ID, \"%06X\", ESP.getChipId());\n  sprintf(MQTT_AVAILABILITY_TOPIC, MQTT_AVAILABILITY_TOPIC_TEMPLATE, MQTT_CLIENT_ID);\n\n  DEBUG_PRINT(F(\"INFO: MQTT availability topic: \"));\n  DEBUG_PRINTLN(MQTT_AVAILABILITY_TOPIC);\n  \n#if defined(MOTION_SENSOR)\n  sprintf(MQTT_MOTION_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, MOTION_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT motion sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_MOTION_SENSOR_TOPIC);\n#endif\n#if defined(DOOR_SENSOR)\n  sprintf(MQTT_DOOR_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, DOOR_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT door sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_DOOR_SENSOR_TOPIC);\n#endif\n#if defined(LDR_SENSOR)\n  sprintf(MQTT_LDR_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, LDR_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT luminosity sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_LDR_SENSOR_TOPIC);\n#endif\n#if defined(DHT_SENSOR)\n  sprintf(MQTT_DHT_TEMPERATURE_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, DHT_TEMPERATURE_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT DHT temperature sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_DHT_TEMPERATURE_SENSOR_TOPIC);\n  sprintf(MQTT_DHT_HUMIDITY_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, DHT_HUMIDITY_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT DHT humidity sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_DHT_HUMIDITY_SENSOR_TOPIC);\n#endif\n#if defined(SHT_SENSOR)\n  sprintf(MQTT_SHT_TEMPERATURE_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, SHT_TEMPERATURE_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT SHT temperature sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_SHT_TEMPERATURE_SENSOR_TOPIC);\n  sprintf(MQTT_SHT_HUMIDITY_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, SHT_HUMIDITY_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT SHT humidity sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_SHT_HUMIDITY_SENSOR_TOPIC);\n#endif\n#if defined(BUTTON_SENSOR)\n  sprintf(MQTT_BUTTON_SENSOR_TOPIC, MQTT_SENSOR_TOPIC_TEMPLATE, MQTT_CLIENT_ID, BUTTON_SENSOR_NAME);\n  DEBUG_PRINT(F(\"INFO: MQTT button sensor topic: \"));\n  DEBUG_PRINTLN(MQTT_BUTTON_SENSOR_TOPIC);\n#endif\n\n  mqttClient.setServer(MQTT_SERVER, MQTT_SERVER_PORT);\n\n  connectToMQTT();\n}\n\nvoid loop() {\n  connectToMQTT();\n  mqttClient.loop();\n\n  yield();\n  \n  ms.loop();\n\n  yield();\n  \n#if defined(OTA)\n  handleOTA();\n  yield();\n#endif\n}\n"
  },
  {
    "path": "ha_mqtt_rgb_light/README.md",
    "content": "# MQTT RGB Light - Home Assistant\nA simple example to control a RGB led connected to a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nlight:\n  platform: mqtt\n  name: 'Office RGB light'\n  state_topic: 'office/rgb1/light/status'\n  command_topic: 'office/rgb1/light/switch'\n  brightness_state_topic: 'office/rgb1/brightness/status'\n  brightness_command_topic: 'office/rgb1/brightness/set'\n  rgb_state_topic: 'office/rgb1/rgb/status'\n  rgb_command_topic: 'office/rgb1/rgb/set'\n  brightness_scale: 100\n  optimistic: false\n```\n\n## Schematic\n- LED leg 1 - Resistor 270 Ohms - D1/GPIO5\n- LED leg 2 (longuest leg) - GND\n- LED leg 3 - Resistor 270 Ohms - D2/GPIO4\n- LED leg 4 - Resistor 270 Ohms - D3/GPIO0\n\n![Schematic](Schematic.png)\n\n## Demo\n[![Home-Assistant + MQTT + RGB light](screenshot.png)](https://www.youtube.com/watch?v=7rMpCZ9I2BU \"Home-Assistant + MQTT + RGB light\")\n"
  },
  {
    "path": "ha_mqtt_rgb_light/ha_mqtt_rgb_light.ino",
    "content": "/*\n   MQTT RGB Light for Home-Assistant - NodeMCU (ESP8266)\n   https://home-assistant.io/components/light.mqtt/\n\n   Libraries :\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n\n   Sources :\n    - File > Examples > ES8266WiFi > WiFiClient\n    - File > Examples > PubSubClient > mqtt_auth\n    - File > Examples > PubSubClient > mqtt_esp8266\n    - http://forum.arduino.cc/index.php?topic=272862.0\n\n   Schematic :\n    - https://github.com/mertenats/open-home-automation/blob/master/ha_mqtt_rgb_light/Schematic.png\n    - LED leg 1 - Resistor 270 Ohms - D1/GPIO5\n    - LED leg 2 (longuest leg) - GND\n    - LED leg 3 - Resistor 270 Ohms - D2/GPIO4\n    - LED leg 4 - Resistor 270 Ohms - D3/GPIO0\n\n   Configuration (HA) : \n    light:\n      platform: mqtt\n      name: 'Office RGB light'\n      state_topic: 'office/rgb1/light/status'\n      command_topic: 'office/rgb1/light/switch'\n      brightness_state_topic: 'office/rgb1/brightness/status'\n      brightness_command_topic: 'office/rgb1/brightness/set'\n      rgb_state_topic: 'office/rgb1/rgb/status'\n      rgb_command_topic: 'office/rgb1/rgb/set'\n      brightness_scale: 100\n      optimistic: false\n\n   Samuel M. - v1.1 - 08.2016\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wifi: SSID and password\nconst char* WIFI_SSID = \"[Redacted]\";\nconst char* WIFI_PASSWORD = \"[Redacted]\";\n\n// MQTT: ID, server IP, port, username and password\nconst PROGMEM char* MQTT_CLIENT_ID = \"office_rgb_light\";\nconst PROGMEM char* MQTT_SERVER_IP = \"[Redacted]\";\nconst PROGMEM uint16_t MQTT_SERVER_PORT = 1883;\nconst PROGMEM char* MQTT_USER = \"[Redacted]\";\nconst PROGMEM char* MQTT_PASSWORD = \"[Redacted]\";\n\n// MQTT: topics\n// state\nconst PROGMEM char* MQTT_LIGHT_STATE_TOPIC = \"office/rgb1/light/status\";\nconst PROGMEM char* MQTT_LIGHT_COMMAND_TOPIC = \"office/rgb1/light/switch\";\n\n// brightness\nconst PROGMEM char* MQTT_LIGHT_BRIGHTNESS_STATE_TOPIC = \"office/rgb1/brightness/status\";\nconst PROGMEM char* MQTT_LIGHT_BRIGHTNESS_COMMAND_TOPIC = \"office/rgb1/brightness/set\";\n\n// colors (rgb)\nconst PROGMEM char* MQTT_LIGHT_RGB_STATE_TOPIC = \"office/rgb1/rgb/status\";\nconst PROGMEM char* MQTT_LIGHT_RGB_COMMAND_TOPIC = \"office/rgb1/rgb/set\";\n\n// payloads by default (on/off)\nconst PROGMEM char* LIGHT_ON = \"ON\";\nconst PROGMEM char* LIGHT_OFF = \"OFF\";\n\n// variables used to store the state, the brightness and the color of the light\nboolean m_rgb_state = false;\nuint8_t m_rgb_brightness = 100;\nuint8_t m_rgb_red = 255;\nuint8_t m_rgb_green = 255;\nuint8_t m_rgb_blue = 255;\n\n// pins used for the rgb led (PWM)\nconst PROGMEM uint8_t RGB_LIGHT_RED_PIN = 5;\nconst PROGMEM uint8_t RGB_LIGHT_GREEN_PIN = 0;\nconst PROGMEM uint8_t RGB_LIGHT_BLUE_PIN = 4;\n\n// buffer used to send/receive data with MQTT\nconst uint8_t MSG_BUFFER_SIZE = 20;\nchar m_msg_buffer[MSG_BUFFER_SIZE]; \n\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\n\n// function called to adapt the brightness and the color of the led\nvoid setColor(uint8_t p_red, uint8_t p_green, uint8_t p_blue) {\n  // convert the brightness in % (0-100%) into a digital value (0-255)\n  uint8_t brightness = map(m_rgb_brightness, 0, 100, 0, 255);\n\n  analogWrite(RGB_LIGHT_RED_PIN, map(p_red, 0, 255, 0, brightness));\n  analogWrite(RGB_LIGHT_GREEN_PIN, map(p_green, 0, 255, 0, brightness));\n  analogWrite(RGB_LIGHT_BLUE_PIN, map(p_blue, 0, 255, 0, brightness));\n}\n\n// function called to publish the state of the led (on/off)\nvoid publishRGBState() {\n  if (m_rgb_state) {\n    client.publish(MQTT_LIGHT_STATE_TOPIC, LIGHT_ON, true);\n  } else {\n    client.publish(MQTT_LIGHT_STATE_TOPIC, LIGHT_OFF, true);\n  }\n}\n\n// function called to publish the brightness of the led (0-100)\nvoid publishRGBBrightness() {\n  snprintf(m_msg_buffer, MSG_BUFFER_SIZE, \"%d\", m_rgb_brightness);\n  client.publish(MQTT_LIGHT_BRIGHTNESS_STATE_TOPIC, m_msg_buffer, true);\n}\n\n// function called to publish the colors of the led (xx(x),xx(x),xx(x))\nvoid publishRGBColor() {\n  snprintf(m_msg_buffer, MSG_BUFFER_SIZE, \"%d,%d,%d\", m_rgb_red, m_rgb_green, m_rgb_blue);\n  client.publish(MQTT_LIGHT_RGB_STATE_TOPIC, m_msg_buffer, true);\n}\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n  // concat the payload into a string\n  String payload;\n  for (uint8_t i = 0; i < p_length; i++) {\n    payload.concat((char)p_payload[i]);\n  }\n  // handle message topic\n  if (String(MQTT_LIGHT_COMMAND_TOPIC).equals(p_topic)) {\n    // test if the payload is equal to \"ON\" or \"OFF\"\n    if (payload.equals(String(LIGHT_ON))) {\n      if (m_rgb_state != true) {\n        m_rgb_state = true;\n        setColor(m_rgb_red, m_rgb_green, m_rgb_blue);\n        publishRGBState();\n      }\n    } else if (payload.equals(String(LIGHT_OFF))) {\n      if (m_rgb_state != false) {\n        m_rgb_state = false;\n        setColor(0, 0, 0);\n        publishRGBState();\n      }\n    }\n  } else if (String(MQTT_LIGHT_BRIGHTNESS_COMMAND_TOPIC).equals(p_topic)) {\n    uint8_t brightness = payload.toInt();\n    if (brightness < 0 || brightness > 100) {\n      // do nothing...\n      return;\n    } else {\n      m_rgb_brightness = brightness;\n      setColor(m_rgb_red, m_rgb_green, m_rgb_blue);\n      publishRGBBrightness();\n    }\n  } else if (String(MQTT_LIGHT_RGB_COMMAND_TOPIC).equals(p_topic)) {\n    // get the position of the first and second commas\n    uint8_t firstIndex = payload.indexOf(',');\n    uint8_t lastIndex = payload.lastIndexOf(',');\n    \n    uint8_t rgb_red = payload.substring(0, firstIndex).toInt();\n    if (rgb_red < 0 || rgb_red > 255) {\n      return;\n    } else {\n      m_rgb_red = rgb_red;\n    }\n    \n    uint8_t rgb_green = payload.substring(firstIndex + 1, lastIndex).toInt();\n    if (rgb_green < 0 || rgb_green > 255) {\n      return;\n    } else {\n      m_rgb_green = rgb_green;\n    }\n    \n    uint8_t rgb_blue = payload.substring(lastIndex + 1).toInt();\n    if (rgb_blue < 0 || rgb_blue > 255) {\n      return;\n    } else {\n      m_rgb_blue = rgb_blue;\n    }\n    \n    setColor(m_rgb_red, m_rgb_green, m_rgb_blue);\n    publishRGBColor();\n  }\n}\n\nvoid reconnect() {\n  // Loop until we're reconnected\n  while (!client.connected()) {\n    Serial.println(\"INFO: Attempting MQTT connection...\");\n    // Attempt to connect\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {\n      Serial.println(\"INFO: connected\");\n      \n      // Once connected, publish an announcement...\n      // publish the initial values\n      publishRGBState();\n      publishRGBBrightness();\n      publishRGBColor();\n\n      // ... and resubscribe\n      client.subscribe(MQTT_LIGHT_COMMAND_TOPIC);\n      client.subscribe(MQTT_LIGHT_BRIGHTNESS_COMMAND_TOPIC);\n      client.subscribe(MQTT_LIGHT_RGB_COMMAND_TOPIC);\n    } else {\n      Serial.print(\"ERROR: failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\"DEBUG: try again in 5 seconds\");\n      // Wait 5 seconds before retrying\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  // init the serial\n  Serial.begin(115200);\n\n  // init the RGB led\n  pinMode(RGB_LIGHT_BLUE_PIN, OUTPUT);\n  pinMode(RGB_LIGHT_RED_PIN, OUTPUT);\n  pinMode(RGB_LIGHT_GREEN_PIN, OUTPUT);\n  analogWriteRange(255);\n  setColor(0, 0, 0);\n\n  // init the WiFi connection\n  Serial.println();\n  Serial.println();\n  Serial.print(\"INFO: Connecting to \");\n  WiFi.mode(WIFI_STA);\n  Serial.println(WIFI_SSID);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n\n  Serial.println(\"\");\n  Serial.println(\"INFO: WiFi connected\");\n  Serial.print(\"INFO: IP address: \");\n  Serial.println(WiFi.localIP());\n\n  // init the MQTT connection\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n}\n"
  },
  {
    "path": "ha_mqtt_rgbw_light_with_discovery/README.md",
    "content": "# MQTT JSON Light - Home Assistant\nA simple example to control a RGB led and a white led connected to a NodeMCU board (ESP8266).\n\n## Features\n- MQTT discovery\n- MQTT JSON Light\n  - State\n  - RGB\n  - White\n  - Brightness\n  - Color temperature\n  - Effect\n    - Rainbow\n\n## How to\n1. Rename `config.example.h`to `config.h`\n2. Define your WiFi SSID and password\n3. Define your MQTT settings\n4. Install the external libraries (PubSubClient, ArduinoJson)\n4. Define `MQTT_MAX_PACKET_SIZE` to `256`in `Arduino/libraries/pubsubclient/src/PubSubClient.h`\n"
  },
  {
    "path": "ha_mqtt_rgbw_light_with_discovery/config.example.h",
    "content": "///////////////////////////////////////////////////////////////////////////\n//   RGB PINS\n///////////////////////////////////////////////////////////////////////////\n#define RED_PIN   D1\n#define GREEN_PIN D2\n#define BLUE_PIN  D3\n#define WHITE_PIN D4\n\n///////////////////////////////////////////////////////////////////////////\n//   MISC\n///////////////////////////////////////////////////////////////////////////\n#define FRIENDLY_NAME \"MQTT RGBW Light\"\n\n///////////////////////////////////////////////////////////////////////////\n//   WiFi\n///////////////////////////////////////////////////////////////////////////\n#define WIFI_SSID     \"\"\n#define WIFI_PASSWORD \"\"\n\n///////////////////////////////////////////////////////////////////////////\n//   MQTT\n///////////////////////////////////////////////////////////////////////////\n#define MQTT_USERNAME     \"\"\n#define MQTT_PASSWORD     \"\"\n#define MQTT_SERVER       \"\"\n#define MQTT_SERVER_PORT  1883\n\n#define MQTT_HOME_ASSISTANT_SUPPORT\n\n#if defined(MQTT_HOME_ASSISTANT_SUPPORT)\n// template: <discovery prefix>/light/<chip ID>/config, status, state or set\n#define MQTT_CONFIG_TOPIC_TEMPLATE  \"%s/light/%s/config\"\n#else\n\n#endif\n\n#define MQTT_STATE_TOPIC_TEMPLATE   \"%s/rgbw/state\"\n#define MQTT_COMMAND_TOPIC_TEMPLATE \"%s/rgbw/set\"\n#define MQTT_STATUS_TOPIC_TEMPLATE  \"%s/rgbw/status\" // MQTT connection: alive/dead\n\n#define MQTT_HOME_ASSISTANT_DISCOVERY_PREFIX  \"homeassistant\"\n#define MQTT_STATE_ON_PAYLOAD   \"ON\"\n#define MQTT_STATE_OFF_PAYLOAD  \"OFF\"\n\n#define MQTT_CONNECTION_TIMEOUT 5000\n\n///////////////////////////////////////////////////////////////////////////\n//   DEBUG\n///////////////////////////////////////////////////////////////////////////\n//#define DEBUG_TELNET\n//#define DEBUG_SERIAL\n\n///////////////////////////////////////////////////////////////////////////\n//   OTA\n///////////////////////////////////////////////////////////////////////////\n#define OTA\n//#define OTA_HOSTNAME  \"hostname\"  // hostname esp8266-[ChipID] by default\n//#define OTA_PASSWORD  \"password\"  // no password by default\n//#define OTA_PORT      8266        // port 8266 by default\n"
  },
  {
    "path": "ha_mqtt_rgbw_light_with_discovery/ha_mqtt_rgbw_light_with_discovery.cpp",
    "content": "#include \"ha_mqtt_rgbw_light_with_discovery.h\"\n\nvolatile uint8_t effect = EFFECT_NOT_DEFINED;\n\n///////////////////////////////////////////////////////////////////////////\n//   CONSTRUCTOR, INIT() AND LOOP()\n///////////////////////////////////////////////////////////////////////////\nAIRGBWBulb::AIRGBWBulb(void) {\n  analogWriteRange(255);\n\n  pinMode(RED_PIN, OUTPUT);  \n  pinMode(GREEN_PIN, OUTPUT);  \n  pinMode(BLUE_PIN, OUTPUT);  \n  pinMode(WHITE_PIN, OUTPUT);  \n}\n\nvoid AIRGBWBulb::init(void) {\n  m_state = false;\n  m_brightness = 255;\n  m_color.red = 0;\n  m_color.green = 0;\n  m_color.blue = 0;\n  m_color.white = 255;\n}\n\nvoid AIRGBWBulb::loop(void) {\n  // TODO: handles effects\n  switch(effect) {\n    case EFFECT_NOT_DEFINED:\n      break;\n    case EFFECT_RAMBOW:\n      static unsigned char count = 0;\n      static unsigned long last = millis();\n      if (millis() - last > EFFECT_RAINBOW_DELAY) {\n        last = millis();\n        rainbowEffect(count++);\n      }\n      break;\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   STATE\n///////////////////////////////////////////////////////////////////////////\nbool AIRGBWBulb::getState(void) {\n  return m_state;\n}\n\nbool AIRGBWBulb::setState(bool p_state) {\n  // checks if the given state is different from the actual state\n  if (p_state == m_state)\n    return false;\n  \n  if (p_state) {\n    m_state = true;\n    setColor();\n  } else {\n    m_state = false;\n    analogWrite(RED_PIN, 0);\n    analogWrite(GREEN_PIN, 0);\n    analogWrite(BLUE_PIN, 0);\n    analogWrite(WHITE_PIN, 0);\n  } \n\n  return true;\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   BRIGHTNESS\n///////////////////////////////////////////////////////////////////////////\nuint8_t AIRGBWBulb::getBrightness(void) {\n  return m_brightness;\n}\n\nbool AIRGBWBulb::setBrightness(uint8_t p_brightness) {\n  // checks if the value is smaller, bigger or equal to the actual brightness value\n  if (p_brightness < 0 || p_brightness > 255 || p_brightness == m_brightness)\n    return false;\n\n  // saves the new brightness value\n  m_brightness = p_brightness;\n\n  if (m_color.white != 0)\n    m_color.white = p_brightness;\n\n  return setColor();\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   RGB COLOR\n///////////////////////////////////////////////////////////////////////////\nColor AIRGBWBulb::getColor(void) {\n  return m_color;\n}\n\nbool AIRGBWBulb::setColor(uint8_t p_red, uint8_t p_green, uint8_t p_blue) {\n  if ((p_red < 0 || p_red > 255) || (p_green < 0 || p_green > 255) || (p_blue < 0 || p_blue > 255))\n    return false;\n\n  // saves the new values\n  m_color.red = p_red;\n  m_color.green = p_green;\n  m_color.blue = p_blue;\n\n  // switches off the white leds\n  m_color.white = 0;\n\n  return setColor();\n}\n\nbool AIRGBWBulb::setColor() {\n  // sets the new color\n  analogWrite(RED_PIN, map(m_color.red, 0, 255, 0, m_brightness));\n  analogWrite(GREEN_PIN, map(m_color.green, 0, 255, 0, m_brightness));\n  analogWrite(BLUE_PIN, map(m_color.blue, 0, 255, 0, m_brightness));\n  analogWrite(WHITE_PIN, m_color.white);\n\n  return true;\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   WHITE COLOR\n///////////////////////////////////////////////////////////////////////////\nbool AIRGBWBulb::setWhite(uint8_t p_white) {\n  // checks if the value is smaller, bigger or equal to the actual white value\n  if (p_white < 0 || p_white > 255 || p_white == m_color.white)\n    return false;\n\n  // saves the new white value\n  m_color.white = p_white;\n  m_brightness = p_white;\n\n  // switch off the RGB leds\n  m_color.red = 0;\n  m_color.green = 0;\n  m_color.blue = 0;\n\n  // adjusts the white value\n  analogWrite(RED_PIN, m_color.red);\n  analogWrite(GREEN_PIN, m_color.green);\n  analogWrite(BLUE_PIN, m_color.blue);\n  analogWrite(WHITE_PIN, m_color.white);\n\n  return true;\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   COLOR TEMPERATURE\n///////////////////////////////////////////////////////////////////////////\nuint16_t AIRGBWBulb::getColorTemperature(void) {\n  return m_colorTemperature;\n}\n\nbool AIRGBWBulb::setColorTemperature(uint16_t p_colorTemperature) {\n  // checks if the value is equal to the actual color temperature\n  if (p_colorTemperature < COLOR_TEMP_HA_MIN_IN_MIRED || p_colorTemperature == m_colorTemperature || p_colorTemperature > COLOR_TEMP_HA_MAX_IN_MIRED)\n    return false;\n\n  // switches off the white leds\n  m_color.white = 0;\n\n  // saves the new colour temperature\n  m_colorTemperature = p_colorTemperature;\n\n  // https://fr.wikipedia.org/wiki/Mired\n  // http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/\n  // M = 1000000 / T <> T [kelvin] = 1000000 / M [mired]\n      int tmpKelvin = 1000000 / m_colorTemperature;\n  \n      if (tmpKelvin < 1000) {\n        tmpKelvin = 1000;\n      } else if (tmpKelvin > 40000) {\n        tmpKelvin = 40000;\n      }\n\n  //int tmpKelvin = map(p_colorTemperature, COLOR_TEMP_HA_MIN_IN_MIRED, COLOR_TEMP_HA_MAX_IN_MIRED, COLOR_TEMP_MAX_IN_KELVIN, COLOR_TEMP_MIN_IN_KELVIN);\n  tmpKelvin = tmpKelvin / 100;\n\n  // computes red\n  if (tmpKelvin <= 66) {\n    m_color.red = 255;\n  } else {\n    float red = tmpKelvin - 60;\n    red = 329.698727446 * pow(red, -0.1332047592);\n    if (red < 0) {\n      m_color.red = 0;\n    } else if (red > 255) {\n      m_color.red = 255;\n    } else {\n      m_color.red = red;\n    }\n  }\n\n  // computes green\n  if (tmpKelvin <= 66) {\n    float green = tmpKelvin;\n    green = 99.4708025861 * log(green) - 161.1195681661;\n    if (green < 0) {\n      m_color.green = 0;\n    } else if (green > 255) {\n      m_color.green = 255;\n    } else {\n      m_color.green = green;\n    }\n  } else {\n    float green = tmpKelvin - 60;\n    green = 288.1221695283 * pow(green, -0.0755148492);\n    if (green < 0) {\n      m_color.green = 0;\n    } else if (green > 255) {\n      m_color.green = 255;\n    } else {\n      m_color.green = green;\n    }\n  }\n\n  // computes blue\n  if (tmpKelvin <= 66) {\n    m_color.blue = 255;\n  } else {\n    if (tmpKelvin <= 19) {\n      m_color.blue = 0;\n    } else {\n      float blue = tmpKelvin - 10;\n      blue = 138.5177312231 * log(blue) - 305.0447927307;\n      if (blue < 0) {\n        m_color.blue = 0;\n      } else if (blue > 255) {\n        m_color.blue = 255;\n      } else {\n        m_color.blue = blue;\n      }\n    }\n  }\n  \n  return setColor();\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   EFFECTS\n///////////////////////////////////////////////////////////////////////////\nbool AIRGBWBulb::setEffect(const char* p_effect) {\n  if (strcmp(p_effect, EFFECT_NOT_DEFINED_NAME) == 0) {\n    effect = EFFECT_NOT_DEFINED;\n    return true;\n  } else if (strcmp(p_effect, EFFECT_RAMBOW_NAME) == 0) {\n    effect = EFFECT_RAMBOW;\n    return true;\n  }\n\n  return false;\n}\n\n// https://github.com/xoseperez/my9291/blob/master/examples/esp8285/esp8285_rainbow.cpp\nvoid AIRGBWBulb::rainbowEffect(uint8_t p_index) {\n  if (p_index < 85) {\n    setColor(p_index * 3, 255 - p_index * 3, 0);\n  } else if (p_index < 170) {\n    p_index -= 85;\n    setColor(255 - p_index * 3, 0, p_index * 3);\n  } else {\n    p_index -= 170;\n    setColor(0, p_index * 3, 255 - p_index * 3);\n  }\n}\n"
  },
  {
    "path": "ha_mqtt_rgbw_light_with_discovery/ha_mqtt_rgbw_light_with_discovery.h",
    "content": "#pragma once\n#ifndef _RGBW_\n#define _RGBW_\n\n#include <ESP8266WiFi.h>          // https://github.com/esp8266/Arduino\n#include \"config.h\"\n\n#define COLOR_TEMP_HA_MIN_IN_MIRED   154    // Home Assistant minimum color temperature\n#define COLOR_TEMP_HA_MAX_IN_MIRED   500    // Home Assistant maximum color temperature\n#define COLOR_TEMP_MIN_IN_KELVIN     1000   // minimum color temperature\n#define COLOR_TEMP_MAX_IN_KELVIN     15000  // maximum color temperature\n\ntypedef struct Color {\n  uint8_t red;\n  uint8_t green;\n  uint8_t blue;\n  uint8_t white;\n};\n\nenum CMD {\n  CMD_NOT_DEFINED,\n  CMD_STATE_CHANGED,\n};\n\n#define EFFECT_NOT_DEFINED_NAME \"None\"\n#define EFFECT_RAMBOW_NAME      \"Rainbow\"\n#define EFFECT_RAINBOW_DELAY    10\n\n#define EFFECT_LIST EFFECT_RAMBOW_NAME\n\nenum EFFECT {\n  EFFECT_NOT_DEFINED,\n  EFFECT_RAMBOW,\n};\n\nclass AIRGBWBulb {\n  public:\n    AIRGBWBulb(void);\n    \n    void      init(void);\n    void      loop(void);\n    \n    bool      getState(void);\n    bool      setState(bool p_state);\n    \n    uint8_t   getBrightness(void);\n    bool      setBrightness(uint8_t p_brightness);\n    \n    Color     getColor(void);\n    bool      setColor(uint8_t p_red, uint8_t p_green, uint8_t p_blue);\n    \n    bool      setWhite(uint8_t p_white);\n    \n    uint16_t  getColorTemperature(void);\n    bool      setColorTemperature(uint16_t p_colorTemperature);\n    \n    bool      setEffect(const char* p_effect);\n\n  private:\n    bool      m_state;    \n    uint8_t   m_brightness;\n    Color     m_color;\n    uint16_t  m_colorTemperature;\n    \n    bool      setColor();\n\n    void      rainbowEffect(uint8_t p_index);\n\n};\n\n#endif\n"
  },
  {
    "path": "ha_mqtt_rgbw_light_with_discovery/ha_mqtt_rgbw_light_with_discovery.ino",
    "content": "/*\n  MQTT Discovery and MQTT JSON Light for Home Assistant\n  \n  Samuel Mertenat\n  04.2017\n*/\n\n#include <ESP8266WiFi.h>          // https://github.com/esp8266/Arduino\n#include <PubSubClient.h>         // https://github.com/knolleary/pubsubclient\n#include <ArduinoJson.h>          // https://github.com/bblanchon/ArduinoJson\n#include <ArduinoOTA.h>\n#include \"ha_mqtt_rgbw_light_with_discovery.h\"\n\n#if defined(DEBUG_TELNET)\nWiFiServer  telnetServer(23);\nWiFiClient  telnetClient;\n#define     DEBUG_PRINT(x)    telnetClient.print(x)\n#define     DEBUG_PRINTLN(x)  telnetClient.println(x)\n#elif defined(DEBUG_SERIAL)\n#define     DEBUG_PRINT(x)    Serial.print(x)\n#define     DEBUG_PRINTLN(x)  Serial.println(x)\n#else\n#define     DEBUG_PRINT(x)\n#define     DEBUG_PRINTLN(x)\n#endif\n\n#if defined(MQTT_HOME_ASSISTANT_SUPPORT)\nStaticJsonBuffer<256> staticJsonBuffer;\nchar jsonBuffer[256] = {0};\n#endif\n\nvolatile uint8_t cmd = CMD_NOT_DEFINED;\n\nAIRGBWBulb    bulb;\nWiFiClient    wifiClient;\nPubSubClient  mqttClient(wifiClient);\n\n///////////////////////////////////////////////////////////////////////////\n//   TELNET\n///////////////////////////////////////////////////////////////////////////\n/*\n   Function called to handle Telnet clients\n   https://www.youtube.com/watch?v=j9yW10OcahI\n*/\n#if defined(DEBUG_TELNET)\nvoid handleTelnet(void) {\n  if (telnetServer.hasClient()) {\n    if (!telnetClient || !telnetClient.connected()) {\n      if (telnetClient) {\n        telnetClient.stop();\n      }\n      telnetClient = telnetServer.available();\n    } else {\n      telnetServer.available().stop();\n    }\n  }\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////\n//   WiFi\n///////////////////////////////////////////////////////////////////////////\n/*\n   Function called to handle WiFi events\n*/\nvoid handleWiFiEvent(WiFiEvent_t event) {\n  switch (event) {\n    case WIFI_EVENT_STAMODE_GOT_IP:\n      DEBUG_PRINTLN(F(\"INFO: WiFi connected\"));\n      DEBUG_PRINT(F(\"INFO: IP address: \"));\n      DEBUG_PRINTLN(WiFi.localIP());\n      break;\n    case WIFI_EVENT_STAMODE_DISCONNECTED:\n      DEBUG_PRINTLN(F(\"ERROR: WiFi losts connection\"));\n      /*\n         TODO: Do something smarter than rebooting the device\n      */\n      delay(5000);\n      ESP.restart();\n      break;\n    default:\n      DEBUG_PRINT(F(\"INFO: WiFi event: \"));\n      DEBUG_PRINTLN(event);\n      break;\n  }\n}\n\n/*\n   Function called to setup the connection to the WiFi AP\n*/\nvoid setupWiFi() {\n  DEBUG_PRINT(F(\"INFO: WiFi connecting to: \"));\n  DEBUG_PRINTLN(WIFI_SSID);\n\n  delay(10);\n\n  WiFi.mode(WIFI_STA);\n  WiFi.onEvent(handleWiFiEvent);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  randomSeed(micros());\n}\n\n///////////////////////////////////////////////////////////////////////////\n//   OTA\n///////////////////////////////////////////////////////////////////////////\n#if defined(OTA)\n/*\n   Function called to setup OTA updates\n*/\nvoid setupOTA() {\n#if defined(OTA_HOSTNAME)\n  ArduinoOTA.setHostname(OTA_HOSTNAME);\n  DEBUG_PRINT(F(\"INFO: OTA hostname sets to: \"));\n  DEBUG_PRINTLN(OTA_HOSTNAME);\n#endif\n\n#if defined(OTA_PORT)\n  ArduinoOTA.setPort(OTA_PORT);\n  DEBUG_PRINT(F(\"INFO: OTA port sets to: \"));\n  DEBUG_PRINTLN(OTA_PORT);\n#endif\n\n#if defined(OTA_PASSWORD)\n  ArduinoOTA.setPassword((const char *)OTA_PASSWORD);\n  DEBUG_PRINT(F(\"INFO: OTA password sets to: \"));\n  DEBUG_PRINTLN(OTA_PASSWORD);\n#endif\n\n  ArduinoOTA.onStart([]() {\n    DEBUG_PRINTLN(F(\"INFO: OTA starts\"));\n  });\n  ArduinoOTA.onEnd([]() {\n    DEBUG_PRINTLN(F(\"INFO: OTA ends\"));\n  });\n  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {\n    DEBUG_PRINT(F(\"INFO: OTA progresses: \"));\n    DEBUG_PRINT(progress / (total / 100));\n    DEBUG_PRINTLN(F(\"%\"));\n  });\n  ArduinoOTA.onError([](ota_error_t error) {\n    DEBUG_PRINT(F(\"ERROR: OTA error: \"));\n    DEBUG_PRINTLN(error);\n    if (error == OTA_AUTH_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA auth failed\"));\n    else if (error == OTA_BEGIN_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA begin failed\"));\n    else if (error == OTA_CONNECT_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA connect failed\"));\n    else if (error == OTA_RECEIVE_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA receive failed\"));\n    else if (error == OTA_END_ERROR)\n      DEBUG_PRINTLN(F(\"ERROR: OTA end failed\"));\n  });\n  ArduinoOTA.begin();\n}\n\n/*\n   Function called to handle OTA updates\n*/\nvoid handleOTA() {\n  ArduinoOTA.handle();\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////\n//   MQTT\n///////////////////////////////////////////////////////////////////////////\n\nchar MQTT_CLIENT_ID[7] = {0};\n#if defined(MQTT_HOME_ASSISTANT_SUPPORT)\nchar MQTT_CONFIG_TOPIC[sizeof(MQTT_HOME_ASSISTANT_DISCOVERY_PREFIX) + sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_CONFIG_TOPIC_TEMPLATE) - 4] = {0};\n#else\n\n#endif\n\nchar MQTT_STATE_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_STATE_TOPIC_TEMPLATE) - 2] = {0};\nchar MQTT_COMMAND_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_COMMAND_TOPIC_TEMPLATE) - 2] = {0};\nchar MQTT_STATUS_TOPIC[sizeof(MQTT_CLIENT_ID) + sizeof(MQTT_STATUS_TOPIC_TEMPLATE) - 2] = {0};\n\nvolatile unsigned long lastMQTTConnection = MQTT_CONNECTION_TIMEOUT;\n/*\n   Function called when a MQTT message has arrived\n   @param p_topic   The topic of the MQTT message\n   @param p_payload The payload of the MQTT message\n   @param p_length  The length of the payload\n*/\nvoid handleMQTTMessage(char* p_topic, byte* p_payload, unsigned int p_length) {\n  // concatenates the payload into a string\n  String payload;\n  for (uint8_t i = 0; i < p_length; i++) {\n    payload.concat((char)p_payload[i]);\n  }\n\n  DEBUG_PRINTLN(F(\"INFO: New MQTT message received\"));\n  DEBUG_PRINT(F(\"INFO: MQTT topic: \"));\n  DEBUG_PRINTLN(p_topic);\n  DEBUG_PRINT(F(\"INFO: MQTT payload: \"));\n  DEBUG_PRINTLN(payload);\n  \n  if (String(MQTT_COMMAND_TOPIC).equals(p_topic)) {\n    DynamicJsonBuffer dynamicJsonBuffer;\n    JsonObject& root = dynamicJsonBuffer.parseObject(p_payload);\n    if (!root.success()) {\n      DEBUG_PRINTLN(F(\"ERROR: parseObject() failed\"));\n      return;\n    }\n\n    if (root.containsKey(\"state\")) {\n      if (strcmp(root[\"state\"], MQTT_STATE_ON_PAYLOAD) == 0) {\n        if (bulb.setState(true)) {\n          DEBUG_PRINT(F(\"INFO: State changed to: \"));\n          DEBUG_PRINTLN(bulb.getState());\n          cmd = CMD_STATE_CHANGED;\n        }\n      } else if (strcmp(root[\"state\"], MQTT_STATE_OFF_PAYLOAD) == 0) {\n        // stops the possible current effect\n        bulb.setEffect(EFFECT_NOT_DEFINED_NAME);\n        \n        if (bulb.setState(false)) {\n          DEBUG_PRINT(F(\"INFO: State changed to: \"));\n          DEBUG_PRINTLN(bulb.getState());\n          cmd = CMD_STATE_CHANGED;\n        }\n      }\n    }\n    \n    if (root.containsKey(\"color\")) {\n      // stops the possible current effect\n      bulb.setEffect(EFFECT_NOT_DEFINED_NAME);\n      \n      uint8_t r = root[\"color\"][\"r\"];\n      uint8_t g = root[\"color\"][\"g\"];\n      uint8_t b = root[\"color\"][\"b\"];\n\n      if (bulb.setColor(r, g, b)) {\n        DEBUG_PRINT(F(\"INFO: Color changed to: \"));\n        DEBUG_PRINT(bulb.getColor().red);\n        DEBUG_PRINT(F(\", \"));\n        DEBUG_PRINT(bulb.getColor().green);\n        DEBUG_PRINT(F(\", \"));\n        DEBUG_PRINTLN(bulb.getColor().blue);\n        cmd = CMD_STATE_CHANGED;\n      }\n    }\n\n    if (root.containsKey(\"brightness\")) {\n      if (bulb.setBrightness(root[\"brightness\"])) {\n        DEBUG_PRINT(F(\"INFO: Brightness changed to: \"));\n        DEBUG_PRINTLN(bulb.getBrightness());\n        cmd = CMD_STATE_CHANGED;\n      }\n    }\n\n    if (root.containsKey(\"white_value\")) {\n      // stops the possible current effect\n      bulb.setEffect(EFFECT_NOT_DEFINED_NAME);\n      \n      if (bulb.setWhite(root[\"white_value\"])) {\n        DEBUG_PRINT(F(\"INFO: White changed to: \"));\n        DEBUG_PRINTLN(bulb.getColor().white);\n        cmd = CMD_STATE_CHANGED;\n      }\n    }\n\n    if (root.containsKey(\"color_temp\")) {\n      // stops the possible current effect\n      bulb.setEffect(EFFECT_NOT_DEFINED_NAME);\n      \n      if (bulb.setColorTemperature(root[\"color_temp\"])) {\n        DEBUG_PRINT(F(\"INFO: Color temperature changed to: \"));\n        DEBUG_PRINTLN(bulb.getColorTemperature());\n        cmd = CMD_STATE_CHANGED;\n      }\n    }\n    \n    if (root.containsKey(\"effect\")) {\n      const char* effect = root[\"effect\"];\n      if (bulb.setEffect(effect)) {\n        DEBUG_PRINTLN(F(\"INFO: Effect started\"));\n        cmd = CMD_NOT_DEFINED;\n      }\n    }\n  }\n}\n\n/*\n  Function called to subscribe to a MQTT topic\n*/\nvoid subscribeToMQTT(char* p_topic) {\n  if (mqttClient.subscribe(p_topic)) {\n    DEBUG_PRINT(F(\"INFO: Sending the MQTT subscribe succeeded for topic: \"));\n    DEBUG_PRINTLN(p_topic);\n  } else {\n    DEBUG_PRINT(F(\"ERROR: Sending the MQTT subscribe failed for topic: \"));\n    DEBUG_PRINTLN(p_topic);\n  }\n}\n\n/*\n  Function called to publish to a MQTT topic with the given payload\n*/\nvoid publishToMQTT(char* p_topic, char* p_payload) {\n  if (mqttClient.publish(p_topic, p_payload, true)) {\n    DEBUG_PRINT(F(\"INFO: MQTT message published successfully, topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\", payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  } else {\n    DEBUG_PRINTLN(F(\"ERROR: MQTT message not published, either connection lost, or message too large. Topic: \"));\n    DEBUG_PRINT(p_topic);\n    DEBUG_PRINT(F(\" , payload: \"));\n    DEBUG_PRINTLN(p_payload);\n  }\n}\n\n/*\n  Function called to connect/reconnect to the MQTT broker\n*/\nvoid connectToMQTT() {\n  if (!mqttClient.connected()) {\n    if (lastMQTTConnection + MQTT_CONNECTION_TIMEOUT < millis()) {\n      if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD, MQTT_STATUS_TOPIC, 0, 1, \"dead\")) {\n        DEBUG_PRINTLN(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n        publishToMQTT(MQTT_STATUS_TOPIC, \"alive\");\n\n#if defined(MQTT_HOME_ASSISTANT_SUPPORT)\n        // MQTT discovery for Home Assistant\n        JsonObject& root = staticJsonBuffer.createObject();\n        root[\"name\"] = FRIENDLY_NAME;\n        root[\"platform\"] = \"mqtt_json\";\n        root[\"state_topic\"] = MQTT_STATE_TOPIC;\n        root[\"command_topic\"] = MQTT_COMMAND_TOPIC;\n        root[\"brightness\"] = true;\n        root[\"rgb\"] = true;\n        root[\"white_value\"] = true;\n        root[\"color_temp\"] = true;\n        root[\"effect\"] = true;\n        root[\"effect_list\"] = EFFECT_LIST;\n        root.printTo(jsonBuffer, sizeof(jsonBuffer));\n        publishToMQTT(MQTT_CONFIG_TOPIC, jsonBuffer);\n#endif\n\n        subscribeToMQTT(MQTT_COMMAND_TOPIC);\n      } else {\n        DEBUG_PRINTLN(F(\"ERROR: The connection to the MQTT broker failed\"));\n        DEBUG_PRINT(F(\"INFO: MQTT username: \"));\n        DEBUG_PRINTLN(MQTT_USERNAME);\n        DEBUG_PRINT(F(\"INFO: MQTT password: \"));\n        DEBUG_PRINTLN(MQTT_PASSWORD);\n        DEBUG_PRINT(F(\"INFO: MQTT broker: \"));\n        DEBUG_PRINTLN(MQTT_SERVER);\n      }\n        lastMQTTConnection = millis();\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//  CMD\n///////////////////////////////////////////////////////////////////////////\n\nvoid handleCMD() {\n  switch(cmd) {\n    case CMD_NOT_DEFINED:\n      break;\n    case CMD_STATE_CHANGED:\n      cmd = CMD_NOT_DEFINED;\n      DynamicJsonBuffer dynamicJsonBuffer;\n      JsonObject& root = dynamicJsonBuffer.createObject();\n      root[\"state\"] = bulb.getState() ? MQTT_STATE_ON_PAYLOAD : MQTT_STATE_OFF_PAYLOAD;\n      root[\"brightness\"] = bulb.getBrightness();\n      JsonObject& color = root.createNestedObject(\"color\");\n      color[\"r\"] = bulb.getColor().red;\n      color[\"g\"] = bulb.getColor().green;\n      color[\"b\"] = bulb.getColor().blue;\n      root[\"white_value\"] = bulb.getColor().white;\n      root[\"color_temp\"] = bulb.getColorTemperature();\n      root.printTo(jsonBuffer, sizeof(jsonBuffer));\n      publishToMQTT(MQTT_STATE_TOPIC, jsonBuffer);\n      break;\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//  SETUP() AND LOOP()\n///////////////////////////////////////////////////////////////////////////\n\nvoid setup() {\n#if defined(DEBUG_SERIAL)\n  Serial.begin(115200);\n#elif defined(DEBUG_TELNET)\n  telnetServer.begin();\n  telnetServer.setNoDelay(true);\n#endif\n\n  setupWiFi();\n\n  sprintf(MQTT_CLIENT_ID, \"%06X\", ESP.getChipId());\n#if defined(MQTT_HOME_ASSISTANT_SUPPORT)\n  sprintf(MQTT_CONFIG_TOPIC, MQTT_CONFIG_TOPIC_TEMPLATE, MQTT_HOME_ASSISTANT_DISCOVERY_PREFIX, MQTT_CLIENT_ID);\n  DEBUG_PRINT(F(\"INFO: MQTT config topic: \"));\n  DEBUG_PRINTLN(MQTT_CONFIG_TOPIC);\n#else\n\n#endif\n\n  sprintf(MQTT_STATE_TOPIC, MQTT_STATE_TOPIC_TEMPLATE, MQTT_CLIENT_ID);\n  sprintf(MQTT_COMMAND_TOPIC, MQTT_COMMAND_TOPIC_TEMPLATE, MQTT_CLIENT_ID);\n  sprintf(MQTT_STATUS_TOPIC, MQTT_STATUS_TOPIC_TEMPLATE, MQTT_CLIENT_ID);\n\n  DEBUG_PRINT(F(\"INFO: MQTT state topic: \"));\n  DEBUG_PRINTLN(MQTT_STATE_TOPIC);\n  DEBUG_PRINT(F(\"INFO: MQTT command topic: \"));\n  DEBUG_PRINTLN(MQTT_COMMAND_TOPIC);\n  DEBUG_PRINT(F(\"INFO: MQTT status topic: \"));\n  DEBUG_PRINTLN(MQTT_STATUS_TOPIC);\n\n  mqttClient.setServer(MQTT_SERVER, MQTT_SERVER_PORT);\n  mqttClient.setCallback(handleMQTTMessage);\n\n  connectToMQTT();\n\n#if defined(OTA)\n  setupOTA();\n#endif\n\n  bulb.init();\n\n  cmd = CMD_STATE_CHANGED;\n}\n\nvoid loop() {\n#if defined(DEBUG_TELNET)\n  // handle the Telnet connection\n  handleTelnet();\n#endif\n\n  yield();\n\n#if defined(OTA)\n  handleOTA();\n#endif\n\n  yield();\n\n  connectToMQTT();\n  mqttClient.loop();\n\n  yield();\n\n  handleCMD();\n\n  yield();\n\n  bulb.loop();\n}\n"
  },
  {
    "path": "ha_mqtt_sensor_dht22/README.md",
    "content": "# MQTT Sensor - Temperature and Humidity - Home Assistant\nA simple example to get temperature and humidity every ten minutes from a DHT22 sensor connected to a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nsensor 1:\n  platform: mqtt\n  state_topic: 'office/sensor1'\n  name: 'Temperature'\n  unit_of_measurement: '°C'\n  value_template: '{{ value_json.temperature }}'\n\nsensor 2:\n  platform: mqtt\n  state_topic: 'office/sensor1'\n  name: 'Humidity'\n  unit_of_measurement: '%'\n  value_template: '{{ value_json.humidity }}'\n```\n\n## Schematic\n- DHT22 leg 1 - VCC\n- DHT22 leg 2 - D1/GPIO5 - Resistor 4.7K Ohms - GND\n- DHT22 leg 4 - GND\n- D0/GPIO16 - RST (wake-up purpose)\n\n![Schematic](Schematic.png)\n"
  },
  {
    "path": "ha_mqtt_sensor_dht22/ha_mqtt_sensor_dht22.ino",
    "content": "/*\n   MQTT Sensor - Temperature and Humidity (DHT22) for Home-Assistant - NodeMCU (ESP8266)\n   https://home-assistant.io/components/sensor.mqtt/\n\n   Libraries :\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n    - DHT : https://github.com/adafruit/DHT-sensor-library\n    - ArduinoJson : https://github.com/bblanchon/ArduinoJson\n\n   Sources :\n    - File > Examples > ES8266WiFi > WiFiClient\n    - File > Examples > PubSubClient > mqtt_auth\n    - File > Examples > PubSubClient > mqtt_esp8266\n    - File > Examples > DHT sensor library > DHTtester\n    - File > Examples > ArduinoJson > JsonGeneratorExample\n    - http://www.jerome-bernard.com/blog/2015/10/04/wifi-temperature-sensor-with-nodemcu-esp8266/\n\n   Schematic :\n    - https://github.com/mertenats/open-home-automation/blob/master/ha_mqtt_sensor_dht22/Schematic.png\n    - DHT22 leg 1 - VCC\n    - DHT22 leg 2 - D1/GPIO5 - Resistor 4.7K Ohms - GND\n    - DHT22 leg 4 - GND\n    - D0/GPIO16 - RST (wake-up purpose)\n\n   Configuration (HA) :\n    sensor 1:\n      platform: mqtt\n      state_topic: 'office/sensor1'\n      name: 'Temperature'\n      unit_of_measurement: '°C'\n      value_template: '{{ value_json.temperature }}'\n    \n    sensor 2:\n      platform: mqtt\n      state_topic: 'office/sensor1'\n      name: 'Humidity'\n      unit_of_measurement: '%'\n      value_template: '{{ value_json.humidity }}'\n\n   Samuel M. - v1.1 - 08.2016\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n#include \"DHT.h\"\n#include <ArduinoJson.h>\n\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wifi: SSID and password\nconst char* WIFI_SSID = \"[Redacted]\";\nconst char* WIFI_PASSWORD = \"[Redacted]\";\n\n// MQTT: ID, server IP, port, username and password\nconst PROGMEM char* MQTT_CLIENT_ID = \"office_dht22\";\nconst PROGMEM char* MQTT_SERVER_IP = \"[Redacted]\";\nconst PROGMEM uint16_t MQTT_SERVER_PORT = 1883;\nconst PROGMEM char* MQTT_USER = \"[Redacted]\";\nconst PROGMEM char* MQTT_PASSWORD = \"[Redacted]\";\n\n// MQTT: topic\nconst PROGMEM char* MQTT_SENSOR_TOPIC = \"office/sensor1\";\n\n// sleeping time\nconst PROGMEM uint16_t SLEEPING_TIME_IN_SECONDS = 600; // 10 minutes x 60 seconds\n\n// DHT - D1/GPIO5\n#define DHTPIN 5\n#define DHTTYPE DHT22\n\nDHT dht(DHTPIN, DHTTYPE);\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\n\n// function called to publish the temperature and the humidity\nvoid publishData(float p_temperature, float p_humidity) {\n  // create a JSON object\n  // doc : https://github.com/bblanchon/ArduinoJson/wiki/API%20Reference\n  StaticJsonBuffer<200> jsonBuffer;\n  JsonObject& root = jsonBuffer.createObject();\n  // INFO: the data must be converted into a string; a problem occurs when using floats...\n  root[\"temperature\"] = (String)p_temperature;\n  root[\"humidity\"] = (String)p_humidity;\n  root.prettyPrintTo(Serial);\n  Serial.println(\"\");\n  /*\n     {\n        \"temperature\": \"23.20\" ,\n        \"humidity\": \"43.70\"\n     }\n  */\n  char data[200];\n  root.printTo(data, root.measureLength() + 1);\n  client.publish(MQTT_SENSOR_TOPIC, data, true);\n  yield();\n}\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n}\n\nvoid reconnect() {\n  // Loop until we're reconnected\n  while (!client.connected()) {\n    Serial.println(\"INFO: Attempting MQTT connection...\");\n    // Attempt to connect\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {\n      Serial.println(\"INFO: connected\");\n    } else {\n      Serial.print(\"ERROR: failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\"DEBUG: try again in 5 seconds\");\n      // Wait 5 seconds before retrying\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  // init the serial\n  Serial.begin(115200);\n\n  dht.begin();\n\n  // init the WiFi connection\n  Serial.println();\n  Serial.println();\n  Serial.print(\"INFO: Connecting to \");\n  WiFi.mode(WIFI_STA);\n  Serial.println(WIFI_SSID);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n\n  Serial.println(\"\");\n  Serial.println(\"INFO: WiFi connected\");\n  Serial.println(\"INFO: IP address: \");\n  Serial.println(WiFi.localIP());\n\n  // init the MQTT connection\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n\n  // Reading temperature or humidity takes about 250 milliseconds!\n  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)\n  float h = dht.readHumidity();\n  // Read temperature as Celsius (the default)\n  float t = dht.readTemperature();\n\n  if (isnan(h) || isnan(t)) {\n    Serial.println(\"ERROR: Failed to read from DHT sensor!\");\n    return;\n  } else {\n    //Serial.println(h);\n    //Serial.println(t);\n    publishData(t, h);\n  }\n\n  Serial.println(\"INFO: Closing the MQTT connection\");\n  client.disconnect();\n\n  Serial.println(\"INFO: Closing the Wifi connection\");\n  WiFi.disconnect();\n\n  ESP.deepSleep(SLEEPING_TIME_IN_SECONDS * 1000000, WAKE_RF_DEFAULT);\n  delay(500); // wait for deep sleep to happen\n}\n"
  },
  {
    "path": "ha_mqtt_sensor_photocell/README.md",
    "content": "# MQTT Sensor - Brightness - Home Assistant\nA simple example to get the brightness (0 - 100%) of the room every ten minutes from a photocell connected to a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nsensor 1:\n  platform: mqtt\n  state_topic: 'office/sensor1'\n  name: 'Brightness'\n  unit_of_measurement: '%'\n  value_template: '{{ value_json.brightness }}'\n```\n\n## Schematic\n- Photocell leg 1 - VCC\n- Photocell leg 2 - A0 - Resistor 10K Ohms - GND\n- D0/GPIO16 - RST (wake-up purpose)\n\n![Schematic](Schematic.png)"
  },
  {
    "path": "ha_mqtt_sensor_photocell/ha_mqtt_sensor_photocell.ino",
    "content": "/*\n   MQTT Sensor - Brightness (photocell) for Home-Assistant - NodeMCU (ESP8266)\n   https://home-assistant.io/components/sensor.mqtt/\n\n   Libraries :\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n    - ArduinoJson : https://github.com/bblanchon/ArduinoJson\n\n   Sources :\n    - File > Examples > ES8266WiFi > WiFiClient\n    - File > Examples > PubSubClient > mqtt_auth\n    - File > Examples > PubSubClient > mqtt_esp8266\n    - File > Examples > ArduinoJson > JsonGeneratorExample\n\n   Schematic :\n    - https://github.com/mertenats/open-home-automation/blob/master/ha_mqtt_sensor_photocell/Schematic.png\n    - Photocell leg 1 - VCC\n    - Photocell leg 2 - A0 - Resistor 10K Ohms - GND\n    - D0/GPIO16 - RST (wake-up purpose)\n\n   Configuration (HA) :\n    sensor 1:\n      platform: mqtt\n      state_topic: 'office/sensor1'\n      name: 'Brightness'\n      unit_of_measurement: '%'\n      value_template: '{{ value_json.brightness }}'\n\n   Samuel M. - v1.1 - 08.2016\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n#include <ArduinoJson.h>\n\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wifi: SSID and password\nconst PROGMEM char* WIFI_SSID = \"[Redacted]\";\nconst PROGMEM char* WIFI_PASSWORD = \"[Redacted]\";\n\n// MQTT: ID, server IP, port, username and password\nconst PROGMEM char* MQTT_CLIENT_ID = \"office_brightness\";\nconst PROGMEM char* MQTT_SERVER_IP = \"[Redacted]\";\nconst PROGMEM uint16_t MQTT_SERVER_PORT = 1883;\nconst PROGMEM char* MQTT_USER = \"[Redacted]\";\nconst PROGMEM char* MQTT_PASSWORD = \"[Redacted]\";\n\n// MQTT: topic\nconst PROGMEM char* MQTT_SENSOR_TOPIC = \"office/sensor1\";\n\n// sleeping time\nconst PROGMEM uint16_t SLEEPING_TIME_IN_SECONDS = 600; // 10 minutes x 60 seconds\n\n// Photocell: A0 \nconst PROGMEM uint8_t PHOTOCELL_PIN = 0;\n\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\n\n// function called to publish the temperature and the humidity\nvoid publishData(int p_analogRead) {\n  // convert 0-1024 into a percentage\n  uint8_t brightness = map(p_analogRead, 0, 1024, 0, 100);\n  \n  // create a JSON object\n  // doc : https://github.com/bblanchon/ArduinoJson/wiki/API%20Reference\n  StaticJsonBuffer<200> jsonBuffer;\n  JsonObject& root = jsonBuffer.createObject();\n  root[\"brightness\"] = (String)brightness;\n  root.prettyPrintTo(Serial);\n  Serial.println(\"\");\n  /*\n  {\n    \"brightness\":  \"75\"\n  }\n  */\n  char data[200];\n  root.printTo(data, root.measureLength() + 1);\n  client.publish(MQTT_SENSOR_TOPIC, data);\n}\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n}\n\nvoid reconnect() {\n  // Loop until we're reconnected\n  while (!client.connected()) {\n    Serial.print(\"INFO: Attempting MQTT connection...\");\n    // Attempt to connect\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {\n      Serial.println(\"INFO: connected\");\n    } else {\n      Serial.print(\"ERROR: failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\"DEBUG: try again in 5 seconds\");\n      // Wait 5 seconds before retrying\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  // init the serial\n  Serial.begin(115200);\n\n  // init the WiFi connection\n  Serial.println();\n  Serial.println();\n  Serial.print(\"INFO: Connecting to \");\n  WiFi.mode(WIFI_STA);\n  Serial.println(WIFI_SSID);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n\n  Serial.println(\"\");\n  Serial.println(\"INFO: WiFi connected\");\n  Serial.println(\"INFO: IP address: \");\n  Serial.println(WiFi.localIP());\n\n  // init the MQTT connection\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n\n  // read the value of the photocell\n  uint16_t photocell = analogRead(PHOTOCELL_PIN);\n\n  if (photocell < 0 || photocell > 1024) {\n    Serial.println(\"ERROR: Failed to read from the photocell!\");\n    return;\n  } else {\n    publishData(photocell);\n  }\n\n  Serial.println(\"INFO: Closing the MQTT connection\");\n  client.disconnect();\n\n  Serial.println(\"INFO: Closing the Wifi connection\");\n  WiFi.disconnect();\n\n  ESP.deepSleep(SLEEPING_TIME_IN_SECONDS * 1000000, WAKE_RF_DEFAULT);\n  delay(500); // wait for deep sleep to happen\n}\n"
  },
  {
    "path": "ha_mqtt_switch/README.md",
    "content": "# MQTT Switch - Home Assistant\nA simple example to control a switch connected to a NodeMCU board (ESP8266).\n\n## Configuration\nconfiguration.yaml :\n```yaml\nswitch:\n  platform: mqtt\n  name: 'Office Switch'\n  state_topic: 'office/switch1/status'\n  command_topic: 'office/switch1/set'\n  retain: true\n  optimistic: false\n```\n\n## Schematic\n- Switch leg 1 - VCC\n- Switch leg 2 - D1/GPIO5 - Resistor 10K Ohms - GND\n\n![Schematic](Schematic.png)\n"
  },
  {
    "path": "ha_mqtt_switch/ha_mqtt_switch.ino",
    "content": "/*\n   MQTT Switch for Home-Assistant - NodeMCU (ESP8266)\n   https://home-assistant.io/components/switch.mqtt/\n\n   Libraries :\n    - ESP8266 core for Arduino : https://github.com/esp8266/Arduino\n    - PubSubClient : https://github.com/knolleary/pubsubclient\n    - OneButton : https://github.com/mathertel/OneButton\n\n   Sources :\n    - File > Examples > ES8266WiFi > WiFiClient\n    - File > Examples > PubSubClient > mqtt_auth\n    - File > Examples > PubSubClient > mqtt_esp8266\n    - OneButton : http://www.mathertel.de/Arduino/OneButtonLibrary.aspx\n\n   Schematic :\n    - https://github.com/mertenats/open-home-automation/blob/master/ha_mqtt_switch/Schematic.png\n    - Switch leg 1 - VCC\n    - Switch leg 2 - D1/GPIO5 - Resistor 10K Ohms - GND\n\n   Configuration (HA) :\n    switch:\n      platform: mqtt\n      name: 'Office Switch'\n      state_topic: 'office/switch1/status'\n      command_topic: 'office/switch1/set'\n      retain: true\n      optimistic: false\n\n   Samuel M. - v1.1 - 08.2016\n   If you like this example, please add a star! Thank you!\n   https://github.com/mertenats/open-home-automation\n*/\n\n#include <ESP8266WiFi.h>\n#include <PubSubClient.h>\n#include <OneButton.h>\n\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wifi: SSID and password\nconst char* WIFI_SSID = \"[Redacted]\";\nconst char* WIFI_PASSWORD = \"[Redacted]\";\n\n// MQTT: ID, server IP, port, username and password\nconst PROGMEM char* MQTT_CLIENT_ID = \"office_switch1\";\nconst PROGMEM char* MQTT_SERVER_IP = \"[Redacted]\";\nconst PROGMEM uint16_t MQTT_SERVER_PORT = 1883;\nconst PROGMEM char* MQTT_USER = \"[Redacted]\";\nconst PROGMEM char* MQTT_PASSWORD = \"[Redacted]\";\n\n// MQTT: topics\nconst PROGMEM char* MQTT_SWITCH_STATUS_TOPIC = \"office/switch1/status\";\nconst PROGMEM char* MQTT_SWITCH_COMMAND_TOPIC = \"office/switch1/set\";\n\n// default payload\nconst PROGMEM char* SWITCH_ON = \"ON\";\nconst PROGMEM char* SWITCH_OFF = \"OFF\";\n\n// store the state of the switch\nboolean m_switch_state = false;\n\n// D1/GPIO5\nconst PROGMEM uint8_t BUTTON_PIN = 5;\n\nWiFiClient wifiClient;\nPubSubClient client(wifiClient);\nOneButton button(BUTTON_PIN, false); // false : active HIGH\n\n// function called on button press\n// toggle the state of the switch\nvoid click() {\n  if (m_switch_state) {\n    m_switch_state = false;\n  } else {\n    m_switch_state = true;\n  }\n  publishSwitchState();\n}\n\n// function called to publish the state of the switch (on/off)\nvoid publishSwitchState() {\n  if (m_switch_state) {\n    client.publish(MQTT_SWITCH_STATUS_TOPIC, SWITCH_ON, true);\n  } else {\n    client.publish(MQTT_SWITCH_STATUS_TOPIC, SWITCH_OFF, true);\n  }\n}\n\n// function called when a MQTT message arrived\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n  // concat the payload into a string\n  String payload;\n  for (uint8_t i = 0; i < p_length; i++) {\n    payload.concat((char)p_payload[i]);\n  }\n  // handle message topic\n  if (String(MQTT_SWITCH_COMMAND_TOPIC).equals(p_topic)) {\n    // test if the payload is equal to \"ON\" or \"OFF\"\n    if (payload.equals(String(SWITCH_ON))) {\n      if (m_switch_state != true) {\n        m_switch_state = true;\n        publishSwitchState();\n      }\n    } else if (payload.equals(String(SWITCH_OFF))) {\n      if (m_switch_state != false) {\n        m_switch_state = false;\n        publishSwitchState();\n      }\n    }\n  }\n}\n\nvoid reconnect() {\n  // Loop until we're reconnected\n  while (!client.connected()) {\n    Serial.println(\"INFO: Attempting MQTT connection...\");\n    // Attempt to connect\n    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {\n      Serial.println(\"INFO: connected\");\n      \n      // Once connected, publish an announcement...\n      // publish the initial values\n      publishSwitchState();\n\n      // ... and resubscribe\n      client.subscribe(MQTT_SWITCH_COMMAND_TOPIC);\n    } else {\n      Serial.print(\"ERROR: failed, rc=\");\n      Serial.print(client.state());\n      Serial.println(\"DEBUG: try again in 5 seconds\");\n      // Wait 5 seconds before retrying\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  // init the serial\n  Serial.begin(115200);\n  \n  // link the click function to be called on a single click event.   \n  button.attachClick(click);\n\n  // init the WiFi connection\n  Serial.println();\n  Serial.println();\n  Serial.print(\"INFO: Connecting to \");\n  WiFi.mode(WIFI_STA);\n  Serial.println(WIFI_SSID);\n  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n\n  Serial.println(\"\");\n  Serial.println(\"INFO: WiFi connected\");\n  Serial.println(\"INFO: IP address: \");\n  Serial.println(WiFi.localIP());\n\n  // init the MQTT connection\n  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  // keep watching the push button:\n  button.tick();\n  delay(10);\n  \n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n}\n"
  },
  {
    "path": "openhome/README.md",
    "content": "# HOME AUTOMATION WITH OPEN HARDWARE AND SOFTWARE\n![Features](images/Features.png)\n\n## Table of contents\n1. [Introduction](#introduction)\n2. [Automation](#automation)\n3. [Parts list](#parts-list)\n4. [Installation of the controller](#installation-of-the-controller)\n5. [Installation of the extra components for Home Assistant](#installation-of-the-extra-components-for-home-assistant)\n6. [Implementation of the actuators and sensors](#implementation-of-the-actuators-and-sensors)\n7. [Creation of the automation rules](#creation-of-the-automation-rules)\n8. [Demonstration](#demonstration)\n\n## Introduction\nHome Automation with Open Hardware and Software (a.k.a. OpenHome) was a school project made in a few weeks by a [student](https://www.linkedin.com/in/mertenats) at College of Engineering and Architecture of Fribourg, Switzerland ([HEIA](https://www.heia-fr.ch)).\n\n### Context\nThe main goal of this project is to offer an Open Source alternative to commercialized solutions, like Samsung SmartThings or Philips Hue.\n\nIn this project, [Home Assistant](https://home-assistant.io) is used as the controller and the [MQTT](http://mqtt.org) protocol is used for the communication between the controller and the actuators/sensors.\n\nThe controller is installed on a Raspberry Pi 3 and the actuators/sensors are built on top of [NodeMCU](http://nodemcu.com/index_cn.html) boards (ESP8266).\n\n### Architecture\n\nNetwork architecture:\n![Features](images/Architecture_Network.png)\n\nNote: For simplicity, a NodeMCU module is used to connect two lamps and a sensor. In reality, a module will be used for each lamp or sensor.\n\nApplication architecture:\n![Features](images/Architecture_MQTT.png)\n\n## Automation\nIn this project, only the lightning is automated, based on the departure/arrival of the occupiers, the state of the television in the living room or the occupancy of the bed in the bedroom. The lightning is also used to simulate a presence when nobody's home.\n\nAutomation rule overview:\n\n- Change the lightning when the TV is switched on or off\n- Simulate the sunrise when the alarm clock rings\n- Simulate the sunset when the person is going to bed\n- Simulate a presence when nobody is at home\n\nThe rules are further explained in the chapter [Creation of the automation rules](#creation-of-the-automation-rules).\n\n## Parts list\nHardware:\n\n- 1 Wi-Fi router\n- 1 Raspberry Pi\n- 3 NodeMCU boards (or any module based on an ESP8266 chip)\n- 2 RGB LEDs\n- 4 White LEDs\n- 1 PIR sensor (HC-SR501)\n- 1 Load cell\n- 1 Signal amplifier (HX711)\n- 1 Photo-resistor\n- 1 iBeacon\n- 1 iOS device\n\nSoftware:\n\n- Arduino IDE ([here](https://www.arduino.cc))\n- ESP8266 core for Arduino ([here](https://github.com/esp8266/Arduino))\n- MQTT library ([here](https://github.com/knolleary/pubsubclient))\n- HX711 library ([hre](https://github.com/bogde/HX711))\n\n## Installation of the controller\n### Home Assistant\nTo install Home Assistant easily, a Raspberry Pi All-In-One Installer is available [here](https://home-assistant.io/getting-started/installation-raspberry-pi-all-in-one/). More recently, a Raspberry Pi image was released [here](https://home-assistant.io/blog/2016/10/01/we-have-raspberry-image-now/). This image comes pre-installed with everything we need to get started with Home Assistant. For this project, we just need Home Assistant and the Mosquitto MQTT broker, so I prefer to install everything manually.\n\nFirst, we need to update the system and install some Python dependencies.\n\n```\nsudo apt-get update\nsudo apt-get upgrade\nsudo apt-get install python-pip python3-dev\nsudo pip install --upgrade virtualenv\n```\n\nThen, we create a new system user, `hass`, to execute the service for Home Assistant. This is a good practice to reduce the exposure of the rest of the system and provide a more granular control over permissions.\n\n```\nsudo adduser --system hass\n```\n\nWe create a new directory for Home Assistant and we change its ownership to the new created user.\n\n```\nsudo mkdir /srv/hass\nsudo chown hass /srv/hass\n```\nWe become the new user and we set up a virtual Python environment in the directory we just created. A virtual Python environment is a good practice to avoid interaction with the Python packages used by the system or by others applications. Then, we activate it.\n\n```\nsudo su -s /bin/bash hass\nvirtualenv -p python3 /srv/hass\nsource /srv/hass/bin/activate\n```\nAnd now we are ready to install Home Assistant.\n\n```\npip3 install --upgrade homeassistant\n```\nFinally we can run Home Assistant by typing the command below.\n\n```\nsudo -u hass -H /srv/hass/bin/hass\n```\n\nFor starting Home Assistant on boot, we need to create a service for `systemd`. Someone has already created one and we can just download it.\n\n```\nsudo wget https://raw.githubusercontent.com/home-assistant/home-assistant/master/script/home-assistant%40.service -O /etc/systemd/system/home-assistant@hass.service\n```\n\nThis service needs a little modification. We have to replace `/usr/bin/hass`with `/srv/hass/bin/hass`. The line in question should look like this now `ExecStart=/srv/hass/bin/hass --runner`.\n\n```\nsudo nano /etc/systemd/system/home-assistant@hass.service\n```\n\nWe need to reload `systemd`to make the daemon aware of the new configuration.\n\n```\nsudo systemctl --system daemon-reload\nsudo systemctl enable home-assistant@hass\nsudo systemctl start home-assistant@hass\n```\n\nTo upgrade the system in the future, we just need to type the commands below.\n\n```\nsudo su -s /bin/bash hass\nsource /srv/hass/bin/activate\npip3 install --upgrade homeassistant\n```\n\nIf HTTPS is used (link below), we need to add the following lines into the `configuration.yaml`file.\n\n``` yaml\nhttp:\n  api_password: '[REDACTED]'\n  ssl_certificate: '/etc/letsencrypt/live/[REDACTED]/fullchain.pem'\n  ssl_key: '/etc/letsencrypt/live/[REDACTED]/privkey.pem'\n```\n\nImportant files\n\n- Configuration file: `/home/hass/.homeassistant/configuration.yaml`\n- Logs file: `/home/hass/.homeassistant/home-assistant.log`\n\nThe entire configuration is available [here](configuration/home_assistant).\n\nOptional steps:\n\n- Allow a remote access to Home Assistant and protect the GUI with HTTPS ([here](https://home-assistant.io/blog/2015/12/13/setup-encryption-using-lets-encrypt/)).\n- Use Tor to make remote access anonymous ([here](https://home-assistant.io/cookbook/tor_configuration/)).\n\nSources:\n\n- [Installation in Virtualenv](https://home-assistant.io/getting-started/installation-virtualenv/)\n- [Autostart Using Systemd](https://home-assistant.io/getting-started/autostart-systemd/)\n\n### Mosquitto MQTT broker\nTo install the latest version of Mosquitto, we need to use their new repository.\n\n```\nwget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key\nsudo apt-key add mosquitto-repo.gpg.key\n```\n\nThen we make the repository available to apt and update its informations.\n\n```\ncd /etc/apt/sources.list.d/\nsudo wget http://repo.mosquitto.org/debian/mosquitto-jessie.list\nsudo apt-get update\n```\n\nFinally we can install Mosquitto and its client, for testing purpose.\n\n```\nsudo apt-get install mosquitto mosquitto-clients\n```\n\nThe MQTT protocol provides authentication and ACL functionalities to protect its use.\nTo create a username/password, we just need to use `mosquitto_passwd`.\n\n```\ncd /etc/mosquitto/conf.d/\nsudo touch pwfile\nsudo mosquitto_passwd pwfile ha\n```\n\nAnd to restrict publishing/subscribing, we need to create a `aclfile`, in which we specify the username and the relevant MQTT topics.\n\n```\ncd /etc/mosquitto/conf.d/\nsudo touch aclfile\n```\n\nACL examples:\n\n```\nuser ha\ntopic write entrance/light1/switch topic write entrance/light2/switch\n...\ntopic read entrance/light1/status\ntopic read entrance/light2/status\n```\n\nIf MQTT over TLS (link below), username/password and ACL are used, we need to add the following lines into the `mosquitto.conf`file.\n\n```\nallow_anonymous false\npassword_file /etc/mosquitto/conf.d/pwfile\nacl_file /etc/mosquitto/conf.d/aclfile\nlistener 8883 (optional)\ncafile /etc/mosquitto/certs/ca.crt (optional)\ncertfile /etc/mosquitto/certs/raspberrypi.crt\nkeyfile /etc/mosquitto/certs/raspberrypi.key (optional)\n```\n\nTo link Home Assistant with the Mosquitto broker, the `configuration.yaml`file needs the lines below.\n\n```yaml\nmqtt:\n  broker: 'localhost' #127.0.0.1\n  port: 8883 #1883\n  client_id: 'ha'\n  username: 'ha'\n  password: '[REDACTED]' (optional)\n  certificate: '/etc/mosquitto/certs/ca.crt' (optional)\n```\n\nImportant files:\n\n- Configuration file: `/etc/mosquitto/conf.d/mosquitto.conf`\n- Logs file: `/var/log/mosquitto/mosquitto.log`\n\nThe entire configuration is available [here](configuration/mosquitto).\n\nOptional step:\n\n- Protect MQTT over a secure TLS connection ([here](http://owntracks.org/booklet/guide/broker/)).\n\nSource:\n\n- [Mosquitto Debian repository](https://mosquitto.org/2013/01/mosquitto-debian-repository/\n).\n\n### Homebridge\nThe installation of Homebridge is not mandatory. Homebridge runs on Node.js and this language needs to be installed.\n\nWe start by verifying if `git`and `make`are already installed. It's normally the case on Raspbian Jessie.\n\n```\nsudo apt-get install git make\n```\n\nFirst, we have to install Node.js.\n\n```\ncd Downloads/\nwget https://nodejs.org/dist/latest-v4.x/node-v4.6.0-linux-armv6l.tar.gz\ntar -xvf node-v4.6.0-linux-armv6l.tar.gz\ncd node-v4.6.0-linux-armv6l/\nsudo cp -R * /usr/local/\n```\nAnd install Avahi and dependencies.\n\n```\nsudo apt-get install libavahi-compat-libdnssd-dev screen\n```\n\nFinally we install Homebridge and dependencies.\n\n```\nsudo npm install -g --unsafe-perm homebridge hap-nodejs node-gyp\ncd /usr/local/lib/node_modules/homebridge/\nsudo npm install --unsafe-perm bignum\ncd /usr/local/lib/node_modules/hap-nodejs/node_modules/mdns/\nsudo node-gyp BUILDTYPE=Release rebuild\nsudo npm install -g --unsafe-perm homebridge\n```\n\nTo link Homebridge and Home Assistant together, we have to install this plug-in.\n\n```\nsudo npm install -g homebridge-homeassistant\n```\n\nFor starting Homebridge on boot, we need to create a service for `systemd`. Someone has already created one and we can just download it.\n\n```\ncd ~/Downloads\nwget https://gist.githubusercontent.com/johannrichard/0ad0de1feb6adb9eb61a/raw/7defd3836f4fbe2b98ea5a97 49c4413d024e9623/homebridge\nwget https://gist.githubusercontent.com/johannrichard/0ad0de1feb6adb9eb61a/raw/7defd3836f4fbe2b98ea5a97 49c4413d024e9623/homebridge.service\nsudo cp homebridge /etc/default/\nsudo cp homebridge.service /etc/systemd/system\n```\n\nThen we create a new system user, `homebridge`, to execute the service for Homebridge. We create also a folder `/var/homebridge` for the configuration file.\n\n```\nsudo adduser --system homebridge\nsudo mkdir /var/homebridge\nsudo chown homebridge /var/homebridge\n```\n\nWe need to create a configuration file for Homebridge. This file will be located in `/var/homebridge`, with the content displayed below.\n\n```\nsudo nano /var/homebridge/config.json\n```\n\nconfig.json:\n\n```\n{\n  \"bridge\": {\n    \"name\": \"Homebridge\",\n    \"username\": \"CC:22:3D:E3:CE:30\",\n    \"port\": 51826,\n    \"pin\": \"031-45-154\"\n  },\n  \"description\": \"homebridge-homeassistant\",\n  \"platforms\": [\n    {\n      \"platform\": \"HomeAssistant\",\n      \"name\": \"HomeAssistant\",\n      \"host\": \"http://127.0.0.1:8123\",\n      \"password\": \"yourapipassword\",\n      \"supported_types\": [\"automation\", \"binary_sensor\", \"climate\", \"cover\", \"device_tracker\", \"fan\", \"group\", \"input_boolean\", \"light\", \"lock\", \"media_player\", \"remote\", \"scene\", \"script\", \"sensor\", \"switch\", \"vacuum\"],\n      \"default_visibility\": \"hidden\",\n      \"logging\": true,\n      \"verify_ssl\": true\n    }\n  ]\n}\n```\n\nWe need to reload `systemd`to make the daemon aware of the new configuration.\n\n```\nsudo systemctl daemon-reload\nsudo systemctl enable homebridge\nsudo systemctl start homebridge\n```\n\nAt the end, the Homebridge bridge should be visible inside Apple's Home application.\n\nConfiguration of Homebridge in the Apple Home application:\n\n![Configuration for the Home application](images/Home.png)\n\nSources:\n\n- [Running HomeBridge on a Raspberry Pi](https://github.com/nfarina/homebridge/wiki/Running-HomeBridge-on-a-Raspberry-Pi)\n- [Installing Node.js on a Raspberry Pi 3](https://blog.wia.io/installing-node-js-on-a-raspberry-pi-3)\n- [Home Assistant for Homebridge](https://github.com/home-assistant/homebridge-homeassistant)\n\n## Installation of the extra components for Home Assistant\nSome extra components have to be installed for providing notifications (with Telegram) with weather conditions (with Forecast.io) to the user and for detecting when the user when is entering/leaving the house (with Owntracks and an iBeacon).\n\n### Telegram\nTo use Telegram we need to create a bot. The procedure is described [here](https://core.telegram.org/bots).\n\nConfiguration for Home Assistant:\n\n```yaml\nnotify:\n  platform: telegram\n  api_key: [Redacted]\n  chat_id: [Redacted]\n```\n\n### ~~Forcast.io~~ Dark Sky\nTo use the data from ~~Forecast.io~~ darksky.net a [account](https://darksky.net/dev/register) is necessary to retrieve a `api_key`.\n\nConfiguration for Home Assistant:\n\n```yaml\nsensor:\n  - platform: darksky\n    api_key: [Redacted]\n    monitored_conditions:\n      - precip_probability\n      - temperature\n      - wind_speed\n      - cloud_cover\n      - humidity\n      - pressure\n      - temperature_max\n      - precip_intensity_max\n```\n\n### Owntracks\nConfiguration for Home Assistant:\n\n```yaml\ndevice_tracker:\n  platform: owntracks\n```\nConfiguration for the Owntracks application:\n![Configuration for the Owntracks application](images/Owntracks.png)\n\nNote: The MQTT broker must be accessible from outside the local network and provide a SSL/TLS secure connexion.\n\nSources:\n\n- [Telegram](https://home-assistant.io/components/notify.telegram/)\n- [Forecast.io](https://home-assistant.io/components/sensor.forecast/)\n- [Owntracks](https://home-assistant.io/components/device_tracker.owntracks/)\n\n## Implementation of the actuators and sensors\nThe sketches are available [here](sketches). Before using them, we need to modify the Wi-Fi SSID/password, the MQTT username/password, the desired IP address ant the OTA password. The use of TLS is optional.\n\n```C\n// Wi-Fi: Access Point SSID and password\nconst char*       AP_SSID           = \"[Redacted]\";\nconst char*       AP_PASSWORD       = \"[Redacted]\";\n...\nconst char*       MQTT_USERNAME     = \"entrance\";\nconst char*       MQTT_PASSWORD     = \"[Redacted]\";\n...\n// TLS: The fingerprint of the MQTT broker certificate (SHA1)\n#ifdef TLS\n// openssl x509 -fingerprint -in  <certificate>.crt\nconst char*       CA_FINGERPRINT    = \"[Redacted]\";\n// openssl x509 -subject -in  <certificate>.crt\nconst char*       CA_SUBJECT        = \"[Redacted]\";\n#endif\n...\nconst char*       OTA_PASSWORD      = \"[Redacted]\";\n```\n\n### Entrance\n#### Schematic\n\nLED on the left:\n\n- Shortest leg to GND\n- Longest leg to D1, with a 220 Ohms resistor\n\nLED on the right:\n\n- Shortest leg to GND\n- Longest leg to D2, with a 220 Ohms resistor\n\nPIR sensor:\n\n- Red cable to VIN\n- Yellow cable to D3\n- Black cable to GND\n\n![Schematic of the entrance module](sketches/Entrance/Schematic.png)\n#### Configuration for Home Assistant\n\n```yaml\nlight:\n    # lamp 1\n  - platform: mqtt\n    name: 'Lamp 1'\n    state_topic: 'entrance/light1/status'\n    command_topic: 'entrance/light1/switch' optimistic: false\n    # lamp 2\n  - platform: mqtt\n    name: 'Lamp 2'\n    state_topic: 'entrance/light2/status'\n    command_topic: 'entrance/light2/switch' optimistic: false\n\nbinary_sensor:\n  platform: mqtt\n  name: 'Motion'\n  state_topic: 'entrance/door/motion/status'\n  sensor_class: motion\n```\n### Living room\n#### Schematic\nLED on the left:\n\n- Longest leg to GND\n- Leg on the left to D1, with a 220 Ohms resistor\n- Leg on the middle to D2, with a 220 Ohms resistor\n- Leg on the right to D3, with a 220 Ohms resistor\n\nLED on the right:\n\n- Shortest leg to GND\n- Longest leg to D4, with a 220 Ohms resistor\n\nPhoto-resistor:\n\n- One leg to VCC\n- The other leg to GND, with a 10K Ohms resistor and a cable to A0\n\n![Schematic of the living room module](sketches/Livingroom/Schematic.png)\n\n#### Configuration for Home Assistant\n\n```yaml\nlight:\n    # lamp 3 (RGB)\n  - platform: mqtt\n    name: 'Lamp 3'\n    state_topic: 'livingroom/light1/status'\n    command_topic: 'livingroom/light1/switch'\n    brightness_state_topic: 'livingroom/light1/brightness/status'\n    brightness_command_topic: 'livingroom/light1/brightness/set'\n    rgb_state_topic: 'livingroom/light1/color/status'\n    rgb_command_topic: 'livingroom/light1/color/set'\n    optimistic: false\n\n    # lamp 4\n  - platform: mqtt\n    name: 'Lamp 4'\n    state_topic: 'livingroom/light2/status'\n    command_topic: 'livingroom/light2/switch'\n    optimistic: false\nbinary_sensor:\n  platform: mqtt\n  name: 'TV'\n  state_topic: 'livingroom/tv/status'\n```\n### Bedroom\n#### Schematic\n\nLED on the left:\n\n- Longest leg to GND\n- Leg on the left to D1, with a 220 Ohms resistor\n- Leg on the middle to D2, with a 220 Ohms resistor\n- Leg on the right to D3, with a 220 Ohms resistor\n\nLED on the right:\n\n- Shortest leg to GND\n- Longest leg to D4, with a 220 Ohms resistor\n\nLoad cell to HX711:\n\n- Red cable to E+\n- Black cable to E-\n- White cable to A-\n- Green cable to A+\n\nHX711:\n\n- VCC to VCC\n- GND to GND\n- SCK to D6\n- DT to D5\n\n![Schematic of the bedroom module](sketches/Bedroom/Schematic.png)\n#### Configuration for Home Assistant\n\n```yaml\nlight:\n    # lamp 5 (RGB)\n  - platform: mqtt\n    name: 'Lamp 5'\n    state_topic: 'bedroom/light1/status'\n    command_topic: 'bedroom/light1/switch'\n    brightness_state_topic: 'bedroom/light1/brightness/status'     \n    brightness_command_topic: 'bedroom/light1/brightness/set'\n    rgb_state_topic: 'bedroom/light1/color/status'\n    rgb_command_topic: 'bedroom/light1/color/set'\n    optimistic: false\n    # lamp 6\n  - platform: mqtt\n    name: 'Lamp 6'\n    state_topic: 'bedroom/light2/status'\n    command_topic: 'bedroom/light2/switch'\n    optimistic: false\n\nbinary_sensor:\n  platform: mqtt\n  name: 'Occupancy'\n  state_topic: 'bedroom/bed/occupancy/status' sensor_class: occupancy\n```\n## Creation of the automation rules\n### Entrance\n\n| Scenario | Description           | File  |\n| -------- |-------------| -----|\n| 1a       | Turn on the light 1 when a person is detected if nobody's home, the sun is below and the person is unknown | [here](configuration/home_assistant/automation/automation_1a.yaml) |\n| 1b       | Turn on the lights 1 & 2 when a person is detected if a occupier's at home, the sun is below and the person is unknown | [here](configuration/home_assistant/automation/automation_1b.yaml) |\n| 1c       | Turn on the lights 1, 2 & 4 when a occupier of the home is detected if the sun is below and it's before 22:30 | [here](configuration/home_assistant/automation/automation_1c.yaml) |\n| 1d       | Turn on the lights 1, 2, 5 & 6 when a occupier of the home is detected if the sun is below and it's after 22:30 | [here](configuration/home_assistant/automation/automation_1d.yaml) |\n\n### Living room\n\n| Scenario | Description           | File  |\n| -------- |-------------| -----|\n| 2a       | Set the brightness of the light 3 to 50% and turn off the light 4 when the TV is turned on if the sun is below | [here](configuration/home_assistant/automation/automation_2a.yaml) |\n| 2b       | Set the brightness of the light 3 to 75% when the TV is turned off if the sun is below | [here](configuration/home_assistant/automation/automation_2b.yaml) |\n\n### Bedroom\n\n| Scenario | Description           | File  |\n| -------- |-------------| -----|\n| 3a       | Simulate a sunrise with the light 5 when the alarm clock rings, switch off the light 5 and switch on the light 6, send the weather conditions to the user| [here](configuration/home_assistant/automation/automation_3a.yaml) |\n| 3b       | Simulate a sunset when the occupier is detected in its bed, switch off all the others lights| [here](configuration/home_assistant/automation/automation_3b.yaml) |\n\n### Presence simulation\n\n| Scenario | Description           | File  |\n| -------- |-------------| -----|\n| 4a       | Simulate a presence when nobody's home | [here](configuration/home_assistant/automation/automation_4a.yaml) |\n\n## Demonstration\nFeatures:\n\n- Change the lightning when the TV is switched on or off\n- Simulate the sunrise when the alarm clock rings\n- Simulate the sunset when the person is going to bed\n- Simulate a presence when nobody is at home\n- Control the system with Apple Home application and Siri\n\n[![OpenHome with Home Assistant and MQTT](images/Youtube.png)](https://www.youtube.com/watch?v=Vh-vzFPCF2U \"OpenHome with Home Assistant and MQTT\")\n\n*If you like the content of this repo, please add a star! Thank you!*\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_1a.yaml",
    "content": "alias: 'Switch on the lamp 1 on motion (1a)'\ntrigger:\n  platform: state\n  entity_id: binary_sensor.motion\n  from: 'off'\n  to: 'on'\ncondition:\n  condition: and\n  conditions:\n   - condition: state\n     entity_id: group.all_devices\n     state: 'not_home'\n   - condition: state\n     entity_id: 'sun.sun'\n     state: 'below_horizon'\naction:\n  - service: light.turn_on\n    entity_id: light.lamp_1\n  - delay:\n      minutes: 3\n  - service: light.turn_off\n    entity_id: light.lamp_1\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_1b.yaml",
    "content": "alias: 'Switch on the lamp 1 & 2 on motion (1b)'\ntrigger:\n  platform: state\n  entity_id: binary_sensor.motion\n  from: 'off'\n  to: 'on'\ncondition:\n  condition: and\n  conditions:\n   - condition: state\n     entity_id: group.all_devices\n     state: 'home'\n   - condition: state\n     entity_id: 'sun.sun'\n     state: 'below_horizon'\naction:\n  - service: light.turn_on\n    entity_id:\n     - light.lamp_1\n     - light.lamp_2\n  - delay:\n      minutes: 3\n  - service: light.turn_off\n    entity_id: \n     - light.lamp_1\n     - light.lamp_2\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_1c.yaml",
    "content": "alias: 'Switch on the lamp 1, 2 & 4 on arrival of an inhabitantn (1c)'\ntrigger:\n  platform: state\n  entity_id: device_tracker.samuel_phone\n  from: 'not_home'  \n  to: 'home'\ncondition:\n  condition: and\n  conditions:\n    - condition: time\n      before: '22:30:00'\n    - condition: state\n      entity_id: sun.sun\n      state: 'below_horizon'\naction:\n  - service: light.turn_on\n    entity_id:\n      - light.lamp_1\n      - light.lamp_2\n      - light.lamp_4\n  - delay:\n      minutes: 3\n  - service: light.turn_off\n    entity_id:\n      - light.lamp_1\n      - light.lamp_2\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_1d.yaml",
    "content": "alias: 'Switch on the lamp 1, 2, 5 & 6 on arrival of an inhabitantn (1d)'\ntrigger:\n  platform: state\n  entity_id: device_tracker.samuel_phone\n  from: 'not_home'  \n  to: 'home'\ncondition:\n  condition: and\n  conditions:\n    - condition: time\n      after: '22:30:00'\n    - condition: state\n      entity_id: sun.sun\n      state: 'below_horizon'\naction:\n  - service: light.turn_on\n    entity_id:\n      - light.lamp_1\n      - light.lamp_2\n      - light.lamp_5\n      - light.lamp_6\n  - delay:\n      minutes: 3\n  - service: light.turn_off\n    entity_id:\n      - light.lamp_1\n      - light.lamp_2\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_2a.yaml",
    "content": "alias: 'Switch off the lamp 4 when the TV is turned on (2a)'\ntrigger:\n  platform: state\n  entity_id: binary_sensor.tv\n  from: 'off'  \n  to: 'on'\ncondition:\n  condition: state\n  entity_id: sun.sun\n  state: 'below_horizon'\naction:\n  - service: light.turn_off\n    entity_id: light.lamp_4\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_3\n      brightness: 128\n      rgb_color: [0, 255, 0]\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_2b.yaml",
    "content": "alias: 'Switch on the lamp 4 when the TV is turned off (2b)'\ntrigger:\n  platform: state\n  entity_id: binary_sensor.tv\n  from: 'on'  \n  to: 'off'\ncondition:\n  condition: state\n  entity_id: sun.sun\n  state: 'below_horizon'\naction:\n  service: light.turn_on\n  data:\n    entity_id: light.lamp_3\n    brightness: 192\n    rgb_color: [255, 255, 255]\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_3a.yaml",
    "content": "alias: 'Switch on the lamp 5 progressively (3a)'\ntrigger:\n  platform: template\n  value_template: '{{ now.time().strftime(\"%-H\") == states.sensor.alarm_clock_hour.state and now.time().strftime(\"%-M\") == states.sensor.alarm_clock_minute.state }}'\ncondition:\n  condition: and\n  conditions:\n    - condition: state\n      entity_id: input_boolean.alarm_clock_status\n      state: 'on'\n    - condition: time\n      weekday:\n        - mon\n        - tue\n        - wed\n        - thu\n        - fri\naction:\n  # minute 0 to 1\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 45\n      rgb_color: [255, 0, 0] # red\n  - delay:\n      minutes: 1\n # minute 1 to 2\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 60\n      rgb_color: [255, 51, 51] \n  - delay:\n      minutes: 1\n  # minute 2 to 3\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 75\n      rgb_color: [255, 102, 102] \n  - delay:\n      minutes: 1\n  # minute 3 to 4\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 90\n      rgb_color: [255, 128, 0]\n  - delay:\n      minutes: 1\n  # minute 4 to 5\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 105\n      rgb_color: [255, 153, 51]\n  - delay:\n      minutes: 1\n  # minute 5 to 6\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 120\n      rgb_color: [255, 178, 102]\n  - delay:\n      minutes: 1\n  # minute 6 to 7\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 135\n      rgb_color: [255, 204, 153]\n  - delay:\n      minutes: 1\n  # minute 7 to 8\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 150\n      rgb_color: [255, 229, 204]\n  - delay:\n      minutes: 1\n  # minute 8 to 9\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 165\n      rgb_color: [255, 255, 204]\n  - delay:\n      minutes: 1\n  # minute 9 to 10\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 180\n      rgb_color: [255, 255, 153]\n  - delay:\n      minutes: 1\n  # minute 10 to 11\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 195\n      rgb_color: [255, 255, 102]\n  - delay:\n      minutes: 1\n  # minute 11 to 12\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 210\n      rgb_color: [255, 255, 51]\n  - delay:\n      minutes: 1\n  # minute 12 to 13\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 225\n      rgb_color: [255, 255, 0]\n  - delay:\n      minutes: 1\n  # minute 13 to 14\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 240\n      rgb_color: [255, 255, 255]\n  - delay:\n      minutes: 1\n  # minute 14 to 15\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 255\n      rgb_color: [255, 255, 255]\n  - delay:\n      minutes: 1\n  - service: light.turn_on\n    entity_id: light.lamp_6\n  - service: light.turn_off\n    entity_id: light.lamp_5\n  # https://home-assistant.io/cookbook/notify_if_over_threshold/\n  - service: notify.notify\n    data_template:\n      message: >\n        Hi Sam ! It's time to wake up ! It's {{ states.sensor.forecastio_temperature.state | round(0) }} degrees Celcius outside and the maximum temperature will be {{ states.sensor.forecastio_daily_high_temperature.state | round(0) }}. There's a {{ states.sensor.forecastio_precip_probability.state | round(0) }}% chance of rain today.\n        {% if states('sensor.forecastio_precip_probability') | int > 50 %}\n        Don't forget to bring your favorite umbrella! Have a nice (and rainy) day !\n        {% else %}\n        Have a nice day!\n        {% endif %}\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_3b.yaml",
    "content": "alias: 'Switch off the lamp 5 progressively (3b)'\ntrigger:\n  platform: state\n  entity_id: binary_sensor.occupancy\n  from: 'off'\n  to: 'on'\ncondition:\n  condition: time\n  after: '20:00:00'\n  before: '07:00:00'\naction:\n  - service: light.turn_off\n  # minute 0 to 1\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 255\n      rgb_color: [255, 255, 255]\n  - delay:\n      minutes: 1\n  # minute 1 to 2\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 240\n      rgb_color: [255, 255, 255]\n  - delay:\n      minutes: 1\n  # minute 2 to 3\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 225\n      rgb_color: [255, 255, 0]\n  - delay:\n      minutes: 1\n  # minute 3 to 4\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 210\n      rgb_color: [255, 255, 51]\n  - delay:\n      minutes: 1\n  # minute 4 to 5\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 195\n      rgb_color: [255, 255, 102]\n  - delay:\n      minutes: 1\n  # minute 5 to 6\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 180\n      rgb_color: [255, 255, 153]\n  - delay:\n      minutes: 1\n  # minute 6 to 7\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 165\n      rgb_color: [255, 255, 204]\n  - delay:\n      minutes: 1\n  # minute 7 to 8\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 150\n      rgb_color: [255, 229, 204]\n  - delay:\n      minutes: 1\n  # minute 8 to 9\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 135\n      rgb_color: [255, 204, 153]\n  - delay:\n      minutes: 1\n  # minute 9 to 10\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 120\n      rgb_color: [255, 178, 102]\n  - delay:\n      minutes: 1\n  # minute 10 to 11\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 105\n      rgb_color: [255, 153, 51]\n  - delay:\n      minutes: 1\n  # minute 11 to 12\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 90\n      rgb_color: [255, 128, 0]\n  - delay:\n      minutes: 1\n  # minute 12 to 13\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 75\n      rgb_color: [255, 102, 102]\n  - delay:\n      minutes: 1\n # minute 13 to 14\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 60\n      rgb_color: [255, 51, 51]\n  - delay:\n      minutes: 1\n  # minute 14 to 15\n  - service: light.turn_on\n    data:\n      entity_id: light.lamp_5\n      brightness: 45\n      rgb_color: [255, 0, 0] # red\n  - delay:\n      minutes: 1\n  - service: light.turn_off\n  # set the light 5 into its initial state (withe, brightness 100%)\n  - service: mqtt.publish\n    data:\n      topic: 'bedroom/light1/color/set'\n      payload: '255,255,255'\n  - service: mqtt.publish\n    data:\n      topic: 'bedroom/light1/brightness/set'\n      payload: '255'\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_3c.yaml",
    "content": "alias: 'Switch on the lamp 5 when the person get out of its bed (3c)' \ntrigger:\n  platform: state\n  entity_id: binary_sensor.occupancy\n  from: 'on'\n  to: 'off'\ncondition:\n  condition: time\n  after: '20:00:00'\n  before: '07:00:00'\naction:\n  service: light.turn_on\n  data:\n    entity_id: light.lamp_5\n    brightness: 64\n    rgb_color: [255, 255, 255]\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation/automation_4a.yaml",
    "content": "alias: Simulate presence (4a)'\ntrigger:\n  - platform: state\n    entity_id: group.all_devices\n    from: 'home'\n    to: 'not_home'\n  - platform: sun\n    event: sunset\n  - platform: event\n    event_type: event_simulate_presence\ncondition:  \n  condition: and\n  conditions:\n    - condition: state\n      entity_id: 'sun.sun'\n      state: 'below_horizon'\n    - condition: time\n      before: '23:01:00'\n    - condition: state\n      entity_id: group.all_devices\n      state: 'not_home'\naction:\n  # https://home-assistant.io/cookbook/perform_actions_based_on_input_select/\n  # https://home-assistant.io/getting-started/scripts/\n  - service: light.turn_on\n    data_template:\n      entity_id: >\n        light.lamp_{{ (range(1, 6) | random) }}\n  # wait some seconds (will be in reality in minutes)\n  - delay: '00:{{ (range(2, 10) | random) }}:00'\n  # turn off all devices\n  - service: light.turn_off\n  # wait a little bit before turning on another lamp\n  - delay: '00:00:{{ (range(1, 5) | random) }}'  \n  # generate an event to call again this automation rule\n  - event: event_simulate_presence\n"
  },
  {
    "path": "openhome/configuration/home_assistant/automation.yaml",
    "content": "- !include automation/automation_1a.yaml\n- !include automation/automation_1b.yaml\n- !include automation/automation_1c.yaml\n- !include automation/automation_1d.yaml\n\n- !include automation/automation_2a.yaml\n- !include automation/automation_2b.yaml\n\n- !include automation/automation_3a.yaml\n- !include automation/automation_3b.yaml\n- !include automation/automation_3c.yaml\n\n- !include automation/automation_4a.yaml\n"
  },
  {
    "path": "openhome/configuration/home_assistant/binary_sensors.yaml",
    "content": "- platform: mqtt\n  name: 'Motion'\n  state_topic: 'entrance/door/motion/status'\n  sensor_class: motion\n- platform: mqtt\n  name: 'Occupancy'\n  state_topic: 'bedroom/bed/occupancy/status'\n  sensor_class: occupancy\n- platform: mqtt\n  name: 'TV'\n  state_topic: 'livingroom/tv/status'\n"
  },
  {
    "path": "openhome/configuration/home_assistant/configuration.yaml",
    "content": "homeassistant:\n  # Name of the location where Home Assistant is running\n  name: Home\n  # Location required to calculate the time the sun rises and sets\n  latitude: [REDACTED]\n  longitude: [REDACTED]\n  # Impacts weather/sunrise data\n  elevation: [REDACTED]\n  # metric for Metric, imperial for Imperial\n  unit_system: metric\n  # Pick yours from here: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones\n  time_zone: Europe/Zurich\n  customize: !include customize.yaml\n\n# Show links to resources in log and frontend\n# introduction:\n\n# Enables the frontend\nfrontend:\n\nhttp:\n  api_password: '[REDACTED]'\n  ssl_certificate: '/etc/letsencrypt/live/[REDACTED]/fullchain.pem'\n  ssl_key: '/etc/letsencrypt/live/[REDACTED]/privkey.pem'\n\n# Checks for available updates\nupdater:\n\n# Discover some devices automatically\ndiscovery:\n\n# Allows you to issue voice commands from the frontend in enabled browsers\nconversation:\n\n# Enables support for tracking state changes over time.\nhistory:\n\n# View all events in a logbook\nlogbook:\n\n# Track the sun\nsun:\n\n\nmqtt:\n  broker: 'localhost' #127.0.0.1\n  port: 8883 #1883\n  client_id: 'ha'\n  username: 'ha'\n  password: '[REDACTED]'\n  certificate: '/etc/mosquitto/certs/ca.crt'\n  discovery: true                 # optional\n  discovery_prefix: homeassistant # optional\n\nlight: !include lights.yaml\nsensor: !include sensors.yaml\nbinary_sensor: !include binary_sensors.yaml\ngroup: !include groups.yaml\nautomation: !include automation.yaml\ninput_number: !include input_sliders.yaml\n\ninput_boolean:\n  alarm_clock_status:\n    initial: on\n\nnotify:\n  platform: telegram\n  api_key: [REDACTED]\n  chat_id: [REDACTED]\n\ndevice_tracker:\n  platform: owntracks\n"
  },
  {
    "path": "openhome/configuration/home_assistant/customize.yaml",
    "content": "# lights\nlight.lamp_1:\n  friendly_name: 'Exterior Lamp'\nlight.lamp_2:\n  friendly_name: 'Interior Lamp'\nlight.lamp_3:\n  friendly_name: 'Cosy Lamp'\nlight.lamp_4:\n  friendly_name: 'Ceiling Lamp'\nlight.lamp_5:\n  friendly_name: 'Bedside Lamp'\nlight.lamp_6:\n  friendly_name: 'Principal Lamp'\n\n# binary sensors\n# icon: https://materialdesignicons.com\nbinary_sensor.occupancy:\n  friendly_name: 'Bed Occupancy'\n  icon: mdi:hotel\nbinary_sensor.tv:\n  friendly_name: 'Television'\ndevice_tracker.samuel_phone:\n  friendly_name: 'Samuel'\n\nsun.sun:\n  hidden: true\n\n# Forecast.io\nsensor.forecastio_cloud_coverage:\n  hidden: true\nsensor.forecastio_daily_high_temperature:\n  hidden: true\nsensor.forecastio_daily_max_precip_intensity:\n  hidden: true\nsensor.forecastio_humidity:\n  friendly_name: 'Humidity'\n  icon: mdi:weather-rainy\nsensor.forecastio_precip_probability:\n  hidden: true\nsensor.forecastio_pressure:\n  friendly_name: 'Pressure'\n  icon: mdi:nature\nsensor.forecastio_temperature:\n  friendly_name: 'Temperature'\n  icon: mdi:thermometer\nsensor.forecastio_wind_speed:\n  hidden: true\n\n# alarm clock\ninput_slider.alarm_clock_hour:\n  friendly_name: 'Hour'\n  icon: mdi:timer\ninput_slider.alarm_clock_minute:\n  friendly_name: 'Minute'\n  icon: mdi:timer\ninput_boolean.alarm_clock_status:\n  friendly_name: 'Alarm Clock Status (Week only)'\n  icon: mdi:alarm-check\nsensor.alarm_clock_hour:\n  hidden: true\nsensor.alarm_clock_minute:\n  hidden: true\nsensor.alarm_clock_time:\n  friendly_name: 'Alarm Clock Setting'\n  icon: mdi:alarm\n\n"
  },
  {
    "path": "openhome/configuration/home_assistant/groups.yaml",
    "content": "default_view:\n  view: yes\n  entities:\n    - group.weather\n    - group.occupancy\n    - group.entrance\n    - group.livingroom\n    - group.bedroom\n    - group.alarm_clock\n\nweather:\n  name: 'Weather'\n  entities:\n    - sensor.forecastio_temperature\n    - sensor.forecastio_humidity\n    - sensor.forecastio_pressure\n\noccupancy:\n  name: 'Occupancy'\n  entities:\n    - device_tracker.samuel_phone\n\nentrance:\n  name: 'Entrance'\n  entities:\n    - binary_sensor.motion\n    - light.lamp_1\n    - light.lamp_2\n\nlivingroom:\n  name: 'Living room'\n  entities:\n    - binary_sensor.tv\n    - light.lamp_3\n    - light.lamp_4\n\nbedroom:\n  name: 'Bedroom'\n  entities:\n    - binary_sensor.occupancy\n    - light.lamp_5\n    - light.lamp_6\n\nalarm_clock:\n  name: 'Alarm Clock'\n  entities:\n    - sensor.alarm_clock_time\n    - input_slider.alarm_clock_hour\n    - input_slider.alarm_clock_minute\n    - input_boolean.alarm_clock_status\n"
  },
  {
    "path": "openhome/configuration/home_assistant/input_numbers.yaml",
    "content": "alarm_clock_hour:\n  min: 0\n  max: 23\n  step: 1\n  mode: slider\n\nalarm_clock_minute:\n  min: 0\n  max: 55\n  step: 5\n  mode: slider\n"
  },
  {
    "path": "openhome/configuration/home_assistant/known_devices.yaml",
    "content": "\nsamuel_phone:\n  name: Samuel\n  mac: \n  picture: \n  track: yes\n  hide_if_away: no\n"
  },
  {
    "path": "openhome/configuration/home_assistant/lights.yaml",
    "content": "# lamp 1\n- platform: mqtt\n  name: 'Lamp 1'\n  state_topic: 'entrance/light1/status'\n  command_topic: 'entrance/light1/switch'\n  optimistic: false\n# lamp 2\n- platform: mqtt\n  name: 'Lamp 2'\n  state_topic: 'entrance/light2/status'\n  command_topic: 'entrance/light2/switch'\n  optimistic: false\n# lamp 3 (RGB)\n- platform: mqtt\n  name: 'Lamp 3'\n  state_topic: 'livingroom/light1/status'\n  command_topic: 'livingroom/light1/switch'\n  brightness_state_topic: 'livingroom/light1/brightness/status'\n  brightness_command_topic: 'livingroom/light1/brightness/set'\n  rgb_state_topic: 'livingroom/light1/color/status'\n  rgb_command_topic: 'livingroom/light1/color/set'\n  optimistic: false\n# lamp 4\n- platform: mqtt\n  name: 'Lamp 4'\n  state_topic: 'livingroom/light2/status'\n  command_topic: 'livingroom/light2/switch'\n  optimistic: false\n# lamp 5 (RGB)\n- platform: mqtt\n  name: 'Lamp 5'\n  state_topic: 'bedroom/light1/status'\n  command_topic: 'bedroom/light1/switch'\n  brightness_state_topic: 'bedroom/light1/brightness/status'\n  brightness_command_topic: 'bedroom/light1/brightness/set'\n  rgb_state_topic: 'bedroom/light1/color/status'\n  rgb_command_topic: 'bedroom/light1/color/set'\n  optimistic: false\n# lamp 6\n- platform: mqtt\n  name: 'Lamp 6'\n  state_topic: 'bedroom/light2/status'\n  command_topic: 'bedroom/light2/switch'\n  optimistic: false\n"
  },
  {
    "path": "openhome/configuration/home_assistant/sensors.yaml",
    "content": "- platform: forecast\n  api_key: [Redacted]\n  monitored_conditions:\n    - precip_probability\n    - temperature\n    - wind_speed\n    - cloud_cover\n    - humidity\n    - pressure\n    - temperature_max\n    - precip_intensity_max\n\n-  platform: template\n   sensors:\n     alarm_clock_hour:\n       value_template: '{{ states(\"input_number.alarm_clock_hour\") | round(0) }}'\n     alarm_clock_minute:\n       value_template: '{{ states(\"input_number.alarm_clock_minute\") | round(0) }}'\n     alarm_clock_time:\n       value_template: '{{ states(\"sensor.alarm_clock_hour\") }}:{% if states(\"sensor.alarm_clock_minute\")|length == 1 %}0{% endif %}{{ states(\"sensor.alarm_clock_minute\") }}'\n"
  },
  {
    "path": "openhome/configuration/mosquitto/aclfile",
    "content": "user ha\ntopic write entrance/light1/switch\ntopic write entrance/light2/switch\n\ntopic write livingroom/light1/switch\ntopic write livingroom/light1/brightness/set\ntopic write livingroom/light1/color/set\ntopic write livingroom/light2/switch\n\ntopic write bedroom/light1/switch\ntopic write bedroom/light1/brightness/set\ntopic write bedroom/light1/color/set\ntopic write bedroom/light2/switch\n\ntopic read entrance/light1/status\ntopic read entrance/light2/status\ntopic read entrance/door/motion/status\ntopic read owntracks/samuel/phone\ntopic read owntracks/samuel/phone/event\n\ntopic read livingroom/light1/status\ntopic read livingroom/light1/brightness/status\ntopic read livingroom/light1/color/status\ntopic read livingroom/light2/status\ntopic read livingroom/tv/status\n\ntopic read bedroom/light1/status\ntopic read bedroom/light1/brightness/status\ntopic read bedroom/light1/color/status\ntopic read bedroom/light2/status\ntopic read bedroom/bed/occupancy/status\n\n\nuser entrance\ntopic write entrance/light1/status\ntopic write entrance/light2/status\ntopic write entrance/door/motion/status\n\ntopic read entrance/light1/switch\ntopic read entrance/light2/switch\n\n\nuser livingroom\ntopic write livingroom/light1/status\ntopic write livingroom/light1/brightness/status\ntopic write livingroom/light1/color/status\ntopic write livingroom/light2/status\ntopic write livingroom/tv/status\n\ntopic read livingroom/light1/switch\ntopic read livingroom/light1/brightness/set\ntopic read livingroom/light1/color/set\ntopic read livingroom/light2/switch\n\n\nuser bedroom\ntopic write bedroom/light1/status\ntopic write bedroom/light1/brightness/status\ntopic write bedroom/light1/color/status\ntopic write bedroom/light2/status\ntopic write bedroom/bed/occupancy/status\n\ntopic read bedroom/light1/switch\ntopic read bedroom/light1/brightness/set\ntopic read bedroom/light1/color/set\ntopic read bedroom/light2/switch\n\n\nuser samuel\ntopic write owntracks/samuel/phone\ntopic write owntracks/samuel/phone/event\n"
  },
  {
    "path": "openhome/configuration/mosquitto/mosquitto.conf",
    "content": "# -----------------------------------------------------------------\n# Certificate based SSL/TLS support\n# -----------------------------------------------------------------\n# The following options can be used to enable SSL/TLS support for\n# this listener. Note that the recommended port for MQTT over TLS\n# is 8883, but this must be set manually.\n#\n# See also the mosquitto-tls man page.\n#listener 1883\nlistener 8883\n\n# At least one of cafile or capath must be defined. They both\n# define methods of accessing the PEM encoded Certificate\n# Authority certificates that have signed your server certificate\n# and that you wish to trust.\n# cafile defines the path to a file containing the CA certificates.\n# capath defines a directory that will be searched for files\n# containing the CA certificates. For capath to work correctly, the\n# certificate files must have \".crt\" as the file ending and you must run\n# \"c_rehash <path to capath>\" each time you add/remove a certificate.\n#cafile\n#capath\ncafile /etc/mosquitto/certs/ca.crt\n\n# Path to the PEM encoded server certificate.\n#certfile\ncertfile /etc/mosquitto/certs/raspberrypi.crt\n\n# Path to the PEM encoded keyfile.\n#keyfile\nkeyfile /etc/mosquitto/certs/raspberrypi.key\n\n# =================================================================\n# Security\n# =================================================================\n\n# Boolean value that determines whether clients that connect\n# without providing a username are allowed to connect. If set to\n# false then a password file should be created (see the\n# password_file option) to control authenticated client access.\n# Defaults to true.\nallow_anonymous false\n\n# -----------------------------------------------------------------\n# Default authentication and topic access control\n# -----------------------------------------------------------------\n\n# Control access to the broker using a password file. This file can be\n# generated using the mosquitto_passwd utility. If TLS support is not compiled\n# into mosquitto (it is recommended that TLS support should be included) then\n# plain text passwords are used, in which case the file should be a text file\n# with lines in the format:\n# username:password\n# The password (and colon) may be omitted if desired, although this\n# offers very little in the way of security.\n#\n# See the TLS client require_certificate and use_identity_as_username options\n# for alternative authentication options.\npassword_file /etc/mosquitto/conf.d/pwfile\n\n# Control access to topics on the broker using an access control list\n# file. If this parameter is defined then only the topics listed will\n# have access.\n# If the first character of a line of the ACL file is a # it is treated as a\n# comment.\n# Topic access is added with lines of the format:\n#\n# topic [read|write|readwrite] <topic>\n#\n# The access type is controlled using \"read\", \"write\" or \"readwrite\". This\n# parameter is optional (unless <topic> contains a space character) - if not\n# given then the access is read/write.  <topic> can contain the + or #\n# wildcards as in subscriptions.\n#\n# The first set of topics are applied to anonymous clients, assuming\n# allow_anonymous is true. User specific topic ACLs are added after a\n# user line as follows:\n#\n# user <username>\n#\n# The username referred to here is the same as in password_file. It is\n# not the clientid.\n#\n#\n# If is also possible to define ACLs based on pattern substitution within the\n# topic. The patterns available for substition are:\n#\n# %c to match the client id of the client\n# %u to match the username of the client\n#\n# The substitution pattern must be the only text for that level of hierarchy.\n#\n# The form is the same as for the topic keyword, but using pattern as the\n# keyword.\n# Pattern ACLs apply to all users even if the \"user\" keyword has previously\n# been given.\n#\n# If using bridges with usernames and ACLs, connection messages can be allowed\n# with the following pattern:\n# pattern write $SYS/broker/connection/%c/state\n#\n# pattern [read|write|readwrite] <topic>\n#\n# Example:\n#\n# pattern write sensor/%u/data\n#\nacl_file /etc/mosquitto/conf.d/aclfile\n"
  },
  {
    "path": "openhome/configuration/mosquitto/pwfile",
    "content": "samuel:$6$HagYska+ZBtV0a2a$RA0pgSHa5g6/NoZqbE5N0UwnV++vmxkgbz5gRd+9J4Vh03PEXqi8XpqnMM9iFJ6QVzH/893VE5E1cI6SVGpung==\nha:$6$kvipp6VVJOrqYesh$NOji6P9/91OroPkJdjLcwGo115b0JWuFcC6NoFlVVf+Fd7p07XrAdpDtstOMtDly9acPE3NqrHLSV8/RHwswLw==\nentrance:$6$hxoat1lWtyYxbwwA$DnikUcSz/aIZh12zz0GM0blj2G2EXcv67K4qylmrKCofmahgCQRp7HzkEeqiWsAobu8xic9lynZPOUigDIUtAQ==\nlivingroom:$6$L6286ehtOInn7J/b$Mxeng6igWWzt7Wb6Y+fo58Yukz09O90Kvu5AwsysNycJIj8ETLV66OGNLkQ8e105D10mR4nMz+DeP8fgPL5jHA==\nbedroom:$6$CBpKfzH+97D9j5fM$9zUS/WH/HZBL9WYTUA8XKVkoDnP6q4ObxOILvyPiWiHVFlq03/oNt+TCo1KS62+amN/l5AhJOpSaUY2yi3BedA==\n"
  },
  {
    "path": "openhome/sketches/Bedroom/Bedroom.ino",
    "content": "/*\n  Configuration for Home Assistant:\n    mqtt:\n      broker: 127.0.0.1\n      port: 1883\n      client_id: 'ha'\n      username: 'ha'\n      password: '!ƒha@OpenHome16'\n      \n    light:\n        # lamp 5 (RGB)\n      - platform: mqtt\n        name: 'Lamp 5'\n        state_topic: 'bedroom/light1/status'\n        command_topic: 'bedroom/light1/switch'\n        brightness_state_topic: 'bedroom/light1/brightness/status'\n        brightness_command_topic: 'bedroom/light1/brightness/set'\n        rgb_state_topic: 'bedroom/light1/color/status'\n        rgb_command_topic: 'bedroom/light1/color/set'\n        optimistic: false\n      # lamp 6\n      - platform: mqtt\n        name: 'Lamp 6'\n        state_topic: 'bedroom/light2/status'\n        command_topic: 'bedroom/light2/switch'\n        optimistic: false\n        \n    binary_sensor:\n      - platform: mqtt\n        name: 'Occupancy'\n        state_topic: 'bedroom/bed/occupancy/status'\n        sensor_class: occupancy\n\n  Sources:\n    - MQTT:   File > Examples > PubSubClient > mqtt_esp8266\n    - TLS:    https://io.adafruit.com/blog/security/2016/07/05/adafruit-io-security-esp8266/\n    - OTA:    File > Examples > ArduinoOTA > BasicOTA\n    - HX711:  https://github.com/sparkfun/HX711-Load-Cell-Amplifier/blob/master/firmware/SparkFun_HX711_Example/SparkFun_HX711_Example.ino\n*/\n\n#include <ESP8266WiFi.h>    // https://github.com/esp8266/Arduino (GNUv2.1 licence)\n#include <PubSubClient.h>   // https://github.com/knolleary/pubsubclient (no licence)\n#include \"HX711.h\"          // https://github.com/bogde/HX711 (GNUv2 licence)\n#include <ArduinoOTA.h>\n\n//#define DEBUG\n#define TLS\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wi-Fi: Access Point SSID and password\nconst char*       AP_SSID           = \"[Redacted]\";\nconst char*       AP_PASSWORD       = \"[Redacted]\";\n\n// MQTT: client ID, broker IP address, port, username & password\nconst char*       MQTT_CLIENT_ID    = \"bedroom\";\nconst char*       MQTT_SERVER_IP    = \"192.168.1.10\";\n#ifdef TLS\nconst uint16_t    MQTT_SERVER_PORT  = 8883;\n#else\nconst uint16_t    MQTT_SERVER_PORT  = 1883;\n#endif\nconst char*       MQTT_USERNAME     = \"bedroom\";\nconst char*       MQTT_PASSWORD     = \"[Redacted]\";\n\n// MQTT: topics\n// lamp 5\nconst char*       TOPIC_LIGHT1_STATUS             = \"bedroom/light1/status\";\nconst char*       TOPIC_LIGHT1_BRIGHTNESS_STATUS  = \"bedroom/light1/brightness/status\";\nconst char*       TOPIC_LIGHT1_COLOR_STATUS       = \"bedroom/light1/color/status\";\nconst char*       TOPIC_LIGHT1_COMMAND            = \"bedroom/light1/switch\";\nconst char*       TOPIC_LIGHT1_BRIGHTNESS_COMMAND = \"bedroom/light1/brightness/set\";\nconst char*       TOPIC_LIGHT1_COLOR_COMMAND      = \"bedroom/light1/color/set\";\n// lamp 6\nconst char*       TOPIC_LIGHT2_STATUS             = \"bedroom/light2/status\";\nconst char*       TOPIC_LIGHT2_COMMAND            = \"bedroom/light2/switch\";\n// load cell\nconst char*       TOPIC_LOAD_CELL_STATUS          = \"bedroom/bed/occupancy/status\";\n\n// MQTT: payloads\n// Lamps 3 & 4: \"ON\"/\"OFF\"\nconst char*       PAYLOAD_ON              = \"ON\";\nconst char*       PAYLOAD_OFF             = \"OFF\";\n\nboolean           g_light1_status         = false; // turn off by default\nuint8_t           g_light1_brightness     = 254; // max value by default\nuint8_t           g_light1_color_red      = 255;\nuint8_t           g_light1_color_green    = 255;\nuint8_t           g_light1_color_blue     = 255;\nboolean           g_light2_status         = false;\nfloat             g_load_cell_value       = 0;\nboolean           g_load_cell_status      = false; // nobody in the bed, by default\nuint32_t          g_load_cell_last_change = 0;\nboolean           g_load_cell_status_to_publish = false;\n\n// scalling factor for the load cell\n// calibration sketch: https://github.com/sparkfun/HX711-Load-Cell-Amplifier/tree/master/firmware/SparkFun_HX711_Calibration\nconst int         LOAD_CELL_SCALING_FACTOR  = -7050;\nconst uint8_t     LOAD_CELL_THRESHOLD       = 5;    // +/- 5 lbs\nconst uint16_t    LOAD_CELL_TIME_OFFSET     = 3000; // 3 seconds in the same state before a notification to the controller\n\n// buffer used to send/receive data with MQTT\nconst uint8_t     MSG_BUFFER_SIZE       = 20;\nchar              g_msg_buffer[MSG_BUFFER_SIZE];\n\nconst uint8_t     LIGHT1_RED_PIN        = D3;\nconst uint8_t     LIGHT1_GREEN_PIN      = D2;\nconst uint8_t     LIGHT1_BLUE_PIN       = D1;\nconst uint8_t     LIGHT2_PIN            = D7; // D4 seems to be also connected to a internal LED...\nconst uint8_t     LOAD_CELL_DOUT_PIN    = D6;\nconst uint8_t     LOAD_CELL_CLK_PIN     = D5;\n\n// TLS: The fingerprint of the MQTT broker certificate (SHA1)\n#ifdef TLS\n// openssl x509 -fingerprint -in  <certificate>.crt\nconst char*       CA_FINGERPRINT    = \"[Redacted]\";\n// openssl x509 -subject -in  <certificate>.crt\nconst char*       CA_SUBJECT        = \"[Redacted]\";\n#endif\n\n// Fixed IP address: IP address, IP gateway, subnet, dns\nconst IPAddress   IP                (192, 168,   1, 102);\nconst IPAddress   IP_GATEWAY        (192, 168,   1,   1);\nconst IPAddress   IP_SUBNET         (255, 255, 255,   0);\nconst IPAddress   IP_DNS            (192, 168,   1,   1);\n\n// OTA: Hostname (MQTT_CLIENT_ID) & password\nconst char*       OTA_PASSWORD      = \"[Redacted]\";\n\n// WiFiFlientSecure instead of WiFiClient, for SSL/TLS support\n#ifdef TLS\nWiFiClientSecure  g_wifiClient;\n#else\nWiFiClient  g_wifiClient;\n#endif\nPubSubClient      g_mqttClient(g_wifiClient);\nHX711 g_loadCell(LOAD_CELL_DOUT_PIN, LOAD_CELL_CLK_PIN);\n\n///////////////////////////////////////////////////////////////////////////\n//\n// LIGHT 1 (RGB)\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to publish the status of the light 1\n*/\nvoid publishLight1Status() {\n  if (g_light1_status) {\n    if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT1_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT1_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n/*\n  Function called to publish the brightness status of the light 1\n*/\nvoid publishLight1BrightnessStatus() {\n  snprintf(g_msg_buffer, MSG_BUFFER_SIZE, \"%d\", g_light1_brightness);\n  if (g_mqttClient.publish(TOPIC_LIGHT1_BRIGHTNESS_STATUS, g_msg_buffer, true)) {\n#ifdef DEBUG\n    Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n    Serial.print(TOPIC_LIGHT1_BRIGHTNESS_STATUS);\n    Serial.print(F(\". Payload: \"));\n    Serial.println(g_msg_buffer);\n#endif\n  } else {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n  }\n}\n\n/*\n  Function called to publish the color status of the light 1\n*/\nvoid publishLight1ColorStatus() {\n  snprintf(g_msg_buffer, MSG_BUFFER_SIZE, \"%d,%d,%d\", g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n  if (g_mqttClient.publish(TOPIC_LIGHT1_COLOR_STATUS, g_msg_buffer, true)) {\n#ifdef DEBUG\n    Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n    Serial.print(TOPIC_LIGHT1_COLOR_STATUS);\n    Serial.print(F(\". Payload: \"));\n    Serial.println(g_msg_buffer);\n#endif\n  } else {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n  }\n}\n\n/*\n  Function called to set the color of the light 1\n  @param p_light1_color_red   The value for the red channel\n  @param p_light1_color_green The value for the green channel\n  @param p_light1_color_blue  The value for the blue channel\n*/\n\nvoid setLight1Color(uint8_t p_light1_color_red, uint8_t p_light1_color_green, uint8_t p_light1_color_blue) {\n  analogWrite(LIGHT1_RED_PIN,   p_light1_color_red * g_light1_brightness / 255);\n  analogWrite(LIGHT1_GREEN_PIN, map(p_light1_color_green, 0, 255, 0, g_light1_brightness));\n  analogWrite(LIGHT1_BLUE_PIN,  map(p_light1_color_blue,  0, 255, 0, g_light1_brightness));\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// LIGHT 2\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to publish the status of the light 2\n*/\nvoid publishLight2Status() {\n  if (g_light2_status) {\n    if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT2_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT2_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n/*\n  Function called to switch the status of the light 2\n*/\nvoid setLight2Status() {\n  if (g_light2_status) {\n    digitalWrite(LIGHT2_PIN, HIGH);\n  } else {\n    digitalWrite(LIGHT2_PIN, LOW);\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// LOAD CELL\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to read the load cell\n */\nvoid readLoadCell() {\n  g_load_cell_value = g_loadCell.get_units();\n\n  if (g_load_cell_value > LOAD_CELL_THRESHOLD || g_load_cell_value < -LOAD_CELL_THRESHOLD) {\n    // if someone was already in bed...\n    if (g_load_cell_status) {\n      // if someone was already in bed...\n      // test if he was in the bed for the specified duration\n      if (millis() > g_load_cell_last_change + LOAD_CELL_TIME_OFFSET) {\n        if (g_load_cell_status_to_publish) {\n          g_load_cell_status_to_publish = false;\n          publishLoadCellStatus();\n        }\n      }\n    } else {\n      g_load_cell_last_change = millis();\n      g_load_cell_status = true;\n      g_load_cell_status_to_publish = true;\n    }\n  } else {\n    if (g_load_cell_status) {\n      g_load_cell_last_change = millis();\n      g_load_cell_status = false;\n      g_load_cell_status_to_publish = true;\n    } else {\n      if (millis() > g_load_cell_last_change + LOAD_CELL_TIME_OFFSET) {\n        if (g_load_cell_status_to_publish) {\n          g_load_cell_status_to_publish = false;\n          publishLoadCellStatus();\n        }\n      }\n    }\n  }\n\n#ifdef DEBUG\n  Serial.print(F(\"INFO: Load cell read value: \"));\n  Serial.println(g_load_cell_value);\n#endif\n}\n\n/*\n  Function called to publish the status of the occupancy of the bed\n*/\nvoid publishLoadCellStatus() {\n  if (g_load_cell_status) {\n    if (g_mqttClient.publish(TOPIC_LOAD_CELL_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LOAD_CELL_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_LOAD_CELL_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LOAD_CELL_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// WIFI and TLS\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called to setup the connection to the Wi-Fi Access Point\n*/\nvoid setupWifi() {\n  delay(10);\n  // attempt to connect to the Wi-Fi AP\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(AP_SSID, AP_PASSWORD);\n  // define the fixed IP address\n  WiFi.config(IP, IP_GATEWAY, IP_SUBNET, IP_DNS);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n  }\n\n#ifdef DEBUG\n  Serial.println(F(\"INFO: Client is now connected to the Wi-Fi AP\"));\n  Serial.print(F(\"INFO: IP address: \"));\n  Serial.println(WiFi.localIP());\n#endif\n\n#ifdef TLS\n  verifyFingerprint();\n#endif\n}\n\n/*\n   Function called to verify the fingerprint of the MQTT server and establish a secure connection\n*/\n#ifdef TLS\nvoid verifyFingerprint() {\n  if (!g_wifiClient.connect(MQTT_SERVER_IP, MQTT_SERVER_PORT)) {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: The connection failed to the secure MQTT server\"));\n#endif\n    return;\n  }\n\n  if (g_wifiClient.verify(CA_FINGERPRINT, CA_SUBJECT)) {\n#ifdef DEBUG\n    Serial.println(F(\"INFO: The connection is secure\"));\n#endif\n  } else {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: The given certificate does't match\"));\n#endif\n  }\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////\n//\n// MQTT\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called when a MQTT message arrived\n   @param p_topic   The topic of the MQTT message\n   @param p_payload The payload of the MQTT message\n   @param p_length  The length of the payload\n*/\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n#ifdef DEBUG\n  Serial.println(F(\"INFO: A new MQTT message arrived\"));\n  Serial.print(F(\"INFO: Topic: \"));\n  Serial.println(p_topic);\n  Serial.print(F(\"INFO: Payload: \"));\n  for (int i = 0; i < p_length; i++) {\n    Serial.print((char)p_payload[i]);\n  }\n  Serial.println();\n  Serial.print(F(\"INFO: Length: \"));\n  Serial.println(p_length);\n#endif\n  // handle the MQTT topic of the received message\n  if (String(TOPIC_LIGHT1_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    if (payload.equals(String(PAYLOAD_ON))) {\n      if (g_light1_status != true) {\n        g_light1_status = true;\n        setLight1Color(g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n        publishLight1Status();\n      }\n    } else if (payload.equals(String(PAYLOAD_OFF))) {\n      if (g_light1_status != false) {\n        g_light1_status = false;\n        setLight1Color(LOW, LOW, LOW); // switch off the light\n        publishLight1Status();\n      }\n    }\n  } else if (String(TOPIC_LIGHT1_BRIGHTNESS_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    uint8_t brightness = payload.toInt();\n    if (brightness < 0 || brightness > 255) {\n      // do nothing...\n      return;\n    } else {\n      g_light1_brightness = brightness;\n      setLight1Color(g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n      publishLight1BrightnessStatus();\n    }\n  } else if (String(TOPIC_LIGHT1_COLOR_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    // get the position of the first and second comma\n    uint8_t firstIndex = payload.indexOf(',');\n    uint8_t lastIndex = payload.lastIndexOf(',');\n\n    // get the value for the red color\n    uint8_t red_color = payload.substring(0, firstIndex).toInt();\n    if (red_color < 0 || red_color > 255) {\n      return;\n    } else {\n      g_light1_color_red = red_color;\n    }\n\n    // get the value for the green color\n    uint8_t green_color = payload.substring(firstIndex + 1, lastIndex).toInt();\n    if (green_color < 0 || green_color > 255) {\n      return;\n    } else {\n      g_light1_color_green = green_color;\n    }\n\n    // get the value for the blue color\n    uint8_t blue_color = payload.substring(lastIndex + 1).toInt();\n    if (blue_color < 0 || blue_color > 255) {\n      return;\n    } else {\n      g_light1_color_blue = blue_color;\n    }\n\n    setLight1Color(g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n    publishLight1ColorStatus();\n  } else if (String(TOPIC_LIGHT2_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    if (payload.equals(String(PAYLOAD_ON))) {\n      g_light2_status = true;\n      setLight2Status();\n      publishLight2Status();\n    } else if (payload.equals(String(PAYLOAD_OFF))) {\n      g_light2_status = false;\n      setLight2Status();\n      publishLight2Status();\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: The payload of the MQTT message is not valid\"));\n#endif\n    }\n  } else {\n    // do nothing.....\n#ifdef DEBUG\n    Serial.println(F(\"INFO: The received MQTT message was not used\"));\n#endif\n  }\n}\n\n/*\n   Function called to reconnect the client to the MQTT broker and publish/subscribe to/from some MQTT topics\n*/\nvoid reconnect() {\n  while (!g_mqttClient.connected()) {\n    if (g_mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {\n#ifdef DEBUG\n      Serial.println(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n#endif\n      // subscribe to the light1 command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT1_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COMMAND);\n#endif\n      }\n\n      // subscribe to the light1 brightness command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT1_BRIGHTNESS_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_BRIGHTNESS_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_BRIGHTNESS_COMMAND);\n#endif\n      }\n\n      // subscribe to the light1 brightness command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT1_COLOR_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COLOR_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COLOR_COMMAND);\n#endif\n      }\n\n      // subscribe to the light2 command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT2_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT2_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT2_COMMAND);\n#endif\n      }\n\n      // set the initial status of lights 1 & 2\n      setLight1Color(LOW, LOW, LOW);\n      setLight2Status();\n\n      // publish the initial status of lights 1 & 2\n      publishLight1Status();\n      publishLight1BrightnessStatus();\n      publishLight1ColorStatus();\n      publishLight2Status();\n      publishLoadCellStatus();\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: The connection failed with the MQTT broker\"));\n      Serial.print(\"ERROR: rc: \");\n      Serial.println(g_mqttClient.state());\n      // wait 5 seconds before retrying\n      delay(5000);\n#endif\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// SETUP and LOOP\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called once to initialize the board\n*/\nvoid setup() {\n#ifdef DEBUG\n  Serial.begin(115200);\n  Serial.println(F(\"\\nINFO: The Wi-Fi module is starting...\"));\n#endif\n\n  // init the LEDs as output\n  pinMode(LIGHT1_RED_PIN,     OUTPUT);\n  pinMode(LIGHT1_GREEN_PIN,   OUTPUT);\n  pinMode(LIGHT1_BLUE_PIN,    OUTPUT);\n  pinMode(LIGHT2_PIN,         OUTPUT);\n\n  setupWifi();\n\n  // a wdt reset occurs during the startup\n  // the setup function takes probably more than 1 second\n  // no solution founded yet -> a hard reset is necessary (button rst)\n  // https://github.com/esp8266/Arduino/issues/34\n  //ESP.wdtDisable();\n  //yield();\n  // init the load cell\n  g_loadCell.set_scale(LOAD_CELL_SCALING_FACTOR);\n  g_loadCell.tare();\n  //ESP.wdtEnable(WDTO_8S);\n  //ESP.wdtFeed();\n\n  // set the MQTT broker IP address and port\n  g_mqttClient.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  // set the MQTT callback function\n  g_mqttClient.setCallback(callback);\n\n  // set the hostname & password for OTA\n  ArduinoOTA.setHostname(MQTT_CLIENT_ID);\n  ArduinoOTA.setPassword(OTA_PASSWORD);\n\n#ifdef DEBUG\n  ArduinoOTA.onStart([]() {\n    Serial.println(F(\"INFO: OTA starts\"));\n  });\n  ArduinoOTA.onEnd([]() {\n    Serial.println(F(\"INFO: OTA ends\"));\n  });\n  ArduinoOTA.onError([](ota_error_t error) {\n    Serial.println(F(\"INFO: An error occurs during OTA\"));\n  });\n#endif\n\n  ArduinoOTA.begin();\n\n  // blink the internal LED to indicate the end of the startup\n  pinMode(BUILTIN_LED, OUTPUT);\n  digitalWrite(BUILTIN_LED, LOW);\n  delay(100);\n  digitalWrite(BUILTIN_LED, HIGH);\n  delay(100);\n  digitalWrite(BUILTIN_LED, LOW);\n  delay(100);\n  digitalWrite(BUILTIN_LED, HIGH);\n}\n\n/*\n   Function called infinitely after the setup function\n*/\nvoid loop() {\n  // keep the MQTT client connected to the broker\n  if (!g_mqttClient.connected()) {\n    reconnect();\n  }\n  g_mqttClient.loop();\n\n  yield();\n  //delay(150);\n\n  readLoadCell();\n\n  yield();\n\n  ArduinoOTA.handle();\n  \n  yield();\n}\n"
  },
  {
    "path": "openhome/sketches/Entrance/Entrance.ino",
    "content": "/*\n  Configuration for Home Assistant:\n    mqtt:\n      broker: 127.0.0.1\n      port: 1883\n      client_id: 'ha'\n      username: 'ha'\n      password: '!ha@OpenHome16'\n\n    light:\n      - platform: mqtt\n        name: 'Lamp 1'\n        state_topic: 'entrance/light1/status'\n        command_topic: 'entrance/light1/switch'\n        optimistic: false\n      - platform: mqtt\n        name: 'Lamp 2'\n        state_topic: 'entrance/light2/status'\n        command_topic: 'entrance/light2/switch'\n        optimistic: false\n\n    binary_sensor:\n      - platform: mqtt\n        name: 'Motion'\n        state_topic: 'entrance/door/motion/status'\n        sensor_class: motion\n\n  Sources:\n    - MQTT: File > Examples > PubSubClient > mqtt_esp8266\n    - TLS:  https://io.adafruit.com/blog/security/2016/07/05/adafruit-io-security-esp8266/\n    - OTA:  File > Examples > ArduinoOTA > BasicOTA\n    - PIR:  https://learn.adafruit.com/pir-passive-infrared-proximity-motion-sensor/using-a-pir\n*/\n\n#include <ESP8266WiFi.h>    // https://github.com/esp8266/Arduino (GNUv2.1 licence)\n#include <PubSubClient.h>   // https://github.com/knolleary/pubsubclient (no licence)\n#include <ArduinoOTA.h>\n\n//#define DEBUG\n#define TLS\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wi-Fi: Access Point SSID and password\nconst char*       AP_SSID           = \"[Redacted]\";\nconst char*       AP_PASSWORD       = \"[Redacted]\";\n\n// MQTT: client ID, broker IP address, port, username & password\nconst char*       MQTT_CLIENT_ID    = \"entrance\";\nconst char*       MQTT_SERVER_IP    = \"192.168.1.10\";\n#ifdef TLS\nconst uint16_t    MQTT_SERVER_PORT  = 8883;\n#else\nconst uint16_t    MQTT_SERVER_PORT  = 1883;\n#endif\nconst char*       MQTT_USERNAME     = \"entrance\";\nconst char*       MQTT_PASSWORD     = \"[Redacted]\";\n\n// MQTT: topics\n// lamp 1\nconst char*       TOPIC_LIGHT1_STATUS   = \"entrance/light1/status\";\nconst char*       TOPIC_LIGHT1_COMMAND  = \"entrance/light1/switch\";\n// lamp 2\nconst char*       TOPIC_LIGHT2_STATUS   = \"entrance/light2/status\";\nconst char*       TOPIC_LIGHT2_COMMAND  = \"entrance/light2/switch\";\n// motion sensor\nconst char*       TOPIC_MOTION_STATUS   = \"entrance/door/motion/status\";\n\n// MQTT: payloads\n// Lamps 1 & 2 + motion sensor: \"ON\"/\"OFF\"\nconst char*       PAYLOAD_ON            = \"ON\";\nconst char*       PAYLOAD_OFF           = \"OFF\";\n\nboolean           g_light1_status       = false; // turn off by default\nboolean           g_light2_status       = false;\nvolatile boolean  g_motion_status       = false; // no motion by default\nvolatile boolean  g_motion_change       = false; // no publication to do by default\n\n\nconst uint8_t     LIGHT1_PIN            = D1;\nconst uint8_t     LIGHT2_PIN            = D2;\nconst uint8_t     MOTION_SENSOR_PIN     = D8; // connected before to D3, strange behaviour when D1/D2 was HIGH\n\n// TLS: The fingerprint of the MQTT broker certificate (SHA1)\n#ifdef TLS\n// openssl x509 -fingerprint -in  <certificate>.crt\nconst char*       CA_FINGERPRINT    = \"[Redacted]\";\n// openssl x509 -subject -in  <certificate>.crt\nconst char*       CA_SUBJECT        = \"[Redacted]\";\n#endif\n\n// Fixed IP address: IP address, IP gateway, subnet, dns\nconst IPAddress   IP                (192, 168,   1, 100);\nconst IPAddress   IP_GATEWAY        (192, 168,   1,   1);\nconst IPAddress   IP_SUBNET         (255, 255, 255,   0);\nconst IPAddress   IP_DNS            (192, 168,   1,   1);\n\n// OTA: Hostname (MQTT_CLIENT_ID) & password\nconst char*       OTA_PASSWORD      = \"[Redacted]\";\n\n// WiFiFlientSecure instead of WiFiClient, for SSL/TLS support\n#ifdef TLS\nWiFiClientSecure  g_wifiClient;\n#else\nWiFiClient  g_wifiClient;\n#endif\nPubSubClient      g_mqttClient(g_wifiClient);\n\n///////////////////////////////////////////////////////////////////////////\n//\n// LIGHT 1\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to publish the status of the light 1\n*/\nvoid publishLight1Status() {\n  if (g_light1_status) {\n    if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT1_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT1_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n/*\n  Function called to switch the status of the light 1\n*/\nvoid setLight1Status() {\n  if (g_light1_status) {\n    digitalWrite(LIGHT1_PIN, HIGH);\n  } else {\n    digitalWrite(LIGHT1_PIN, LOW);\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// LIGHT 2\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to publish the status of the light 2\n*/\nvoid publishLight2Status() {\n  if (g_light2_status) {\n    if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT2_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT2_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n/*\n  Function called to switch the status of the light 2\n*/\nvoid setLight2Status() {\n  if (g_light2_status) {\n    digitalWrite(LIGHT2_PIN, HIGH);\n  } else {\n    digitalWrite(LIGHT2_PIN, LOW);\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// MOTION SENSOR\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called when a motion is detected/ended\n*/\nvoid onMotionChanged() {\n  g_motion_status = !g_motion_status;\n  g_motion_change = true;\n}\n\n/*\n  Function called to publish the status of the motion sensor\n*/\nvoid publishMotionStatus() {\n  if (g_motion_status) {\n    if (g_mqttClient.publish(TOPIC_MOTION_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_MOTION_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_MOTION_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_MOTION_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// WIFI and TLS\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called to setup the connection to the Wi-Fi Access Point\n*/\nvoid setupWifi() {\n  delay(10);\n  // attempt to connect to the Wi-Fi AP\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(AP_SSID, AP_PASSWORD);\n  // define the fixed IP address\n  WiFi.config(IP, IP_GATEWAY, IP_SUBNET, IP_DNS);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n  }\n\n#ifdef DEBUG\n  Serial.println(F(\"INFO: Client is now connected to the Wi-Fi AP\"));\n  Serial.print(F(\"INFO: IP address: \"));\n  Serial.println(WiFi.localIP());\n#endif\n\n#ifdef TLS\n  verifyFingerprint();\n#endif\n}\n\n/*\n   Function called to verify the fingerprint of the MQTT server and establish a secure connection\n*/\n#ifdef TLS\nvoid verifyFingerprint() {\n  if (!g_wifiClient.connect(MQTT_SERVER_IP, MQTT_SERVER_PORT)) {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: The connection failed to the secure MQTT server\"));\n#endif\n    return;\n  }\n\n  if (g_wifiClient.verify(CA_FINGERPRINT, CA_SUBJECT)) {\n#ifdef DEBUG\n    Serial.println(F(\"INFO: The connection is secure\"));\n#endif\n  } else {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: The given certificate does't match\"));\n#endif\n  }\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////\n//\n// MQTT\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called when a MQTT message arrived\n   @param p_topic   The topic of the MQTT message\n   @param p_payload The payload of the MQTT message\n   @param p_length  The length of the payload\n*/\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n#ifdef DEBUG\n  Serial.println(F(\"INFO: A new MQTT message arrived\"));\n  Serial.print(F(\"INFO: Topic: \"));\n  Serial.println(p_topic);\n  Serial.print(F(\"INFO: Payload: \"));\n  for (int i = 0; i < p_length; i++) {\n    Serial.print((char)p_payload[i]);\n  }\n  Serial.println();\n  Serial.print(F(\"INFO: Length: \"));\n  Serial.println(p_length);\n#endif\n  // handle the MQTT topic of the received message\n  if (String(TOPIC_LIGHT1_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    if (payload.equals(String(PAYLOAD_ON))) {\n      g_light1_status = true;\n      setLight1Status();\n      publishLight1Status();\n    } else if (payload.equals(String(PAYLOAD_OFF))) {\n      g_light1_status = false;\n      setLight1Status();\n      publishLight1Status();\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: The payload of the MQTT message is not valid\"));\n#endif\n    }\n  } else if (String(TOPIC_LIGHT2_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    if (payload.equals(String(PAYLOAD_ON))) {\n      g_light2_status = true;\n      setLight2Status();\n      publishLight2Status();\n    } else if (payload.equals(String(PAYLOAD_OFF))) {\n      g_light2_status = false;\n      setLight2Status();\n      publishLight2Status();\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: The payload of the MQTT message is not valid\"));\n#endif\n    }\n  } else {\n    // do nothing.....\n#ifdef DEBUG\n    Serial.println(F(\"INFO: The received MQTT message was not used\"));\n#endif\n  }\n}\n\n/*\n   Function called to reconnect the client to the MQTT broker and publish/subscribe to/from some MQTT topics\n*/\nvoid reconnect() {\n  while (!g_mqttClient.connected()) {\n    if (g_mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {\n#ifdef DEBUG\n      Serial.println(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n#endif\n      // subscribe to the light1 command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT1_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COMMAND);\n#endif\n      }\n\n      // subscribe to the light2 command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT2_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT2_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT2_COMMAND);\n#endif\n      }\n\n      // set the initial status of lights 1 & 2\n      setLight1Status();\n      setLight2Status();\n\n      // publish the initial status of lights 1 & 2\n      publishLight1Status();\n      publishLight2Status();\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: The connection failed with the MQTT broker\"));\n      Serial.print(\"ERROR: rc: \");\n      Serial.println(g_mqttClient.state());\n      // wait 5 seconds before retrying\n      delay(5000);\n#endif\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// SETUP and LOOP\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called once to initialize the board\n*/\nvoid setup() {\n#ifdef DEBUG\n  Serial.begin(115200);\n  Serial.println(F(\"\\nINFO: The Wi-Fi module is starting...\"));\n#endif\n\n  // init the LEDs as output, the motion sensor as input\n  pinMode(LIGHT1_PIN,         OUTPUT);\n  pinMode(LIGHT2_PIN,         OUTPUT);\n  pinMode(MOTION_SENSOR_PIN,  INPUT);\n  attachInterrupt(digitalPinToInterrupt(MOTION_SENSOR_PIN), onMotionChanged, CHANGE);\n  pinMode(BUILTIN_LED,        OUTPUT);  // the built-in LED is used to indicate a motion\n  digitalWrite(BUILTIN_LED,   HIGH);    // turn off the built-in LED\n\n\n  setupWifi();\n\n  // set the MQTT broker IP address and port\n  g_mqttClient.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  // set the MQTT callback function\n  g_mqttClient.setCallback(callback);\n\n  // set the hostname & password for OTA\n  ArduinoOTA.setHostname(MQTT_CLIENT_ID);\n  ArduinoOTA.setPassword(OTA_PASSWORD);\n\n#ifdef DEBUG\n  ArduinoOTA.onStart([]() {\n    Serial.println(F(\"INFO: OTA starts\"));\n  });\n  ArduinoOTA.onEnd([]() {\n    Serial.println(F(\"INFO: OTA ends\"));\n  });\n  ArduinoOTA.onError([](ota_error_t error) {\n    Serial.println(F(\"INFO: An error occurs during OTA\"));\n  });\n#endif\n  ArduinoOTA.begin();\n\n  // blink the internal LED to indicate the end of the startup\n  digitalWrite(BUILTIN_LED, LOW);\n  delay(100);\n  digitalWrite(BUILTIN_LED, HIGH);\n  delay(100);\n  digitalWrite(BUILTIN_LED, LOW);\n  delay(100);\n  digitalWrite(BUILTIN_LED, HIGH);\n}\n\n/*\n   Function called infinitely after the setup function\n*/\nvoid loop() {\n  // keep the MQTT client connected to the broker\n  if (!g_mqttClient.connected()) {\n    reconnect();\n  }\n  g_mqttClient.loop();\n\n  yield();\n\n  ArduinoOTA.handle();\n\n  yield();\n  \n  // test if the status of the motion sensor was changed by an interrupt\n  if (g_motion_change) {\n    publishMotionStatus();\n    g_motion_change = false;\n    if (g_motion_status) {\n      digitalWrite(BUILTIN_LED, LOW); // turn on the built-in LED\n#ifdef DEBUG\n      Serial.println(F(\"INFO: Motion detected\"));\n#endif\n    } else {\n      digitalWrite(BUILTIN_LED, HIGH); // turn off the built-in LED\n#ifdef DEBUG\n      Serial.println(F(\"INFO: Motion ended\"));\n#endif\n    }\n  }\n  \n  yield();\n}\n"
  },
  {
    "path": "openhome/sketches/Livingroom/Livingroom.ino",
    "content": "/*\n  Configuration for Home Assistant:\n    mqtt:\n      broker: 127.0.0.1\n      port: 1883\n      client_id: 'ha'\n      username: 'ha'\n      password: '!ha@OpenHome16'\n      \n    light:\n      # lamp 3 (RGB)\n      - platform: mqtt\n        name: 'Lamp 3'\n        state_topic: 'livingroom/light1/status'\n        command_topic: 'livingroom/light1/switch'\n        brightness_state_topic: 'livingroom/light1/brightness/status'\n        brightness_command_topic: 'livingroom/light1/brightness/set'\n        rgb_state_topic: 'livingroom/light1/color/status'\n        rgb_command_topic: 'livingroom/light1/color/set'\n        optimistic: false\n      # lamp 4\n      - platform: mqtt\n        name: 'Lamp 4'\n        state_topic: 'livingroom/light2/status'\n        command_topic: 'livingroom/light2/switch'\n        optimistic: false\n        \n    binary_sensor:\n      - platform: mqtt\n        name: 'TV'\n        state_topic: 'livingroom/tv/status'\n\n  Sources:\n    - MQTT: File > Examples > PubSubClient > mqtt_esp8266\n    - TLS:  https://io.adafruit.com/blog/security/2016/07/05/adafruit-io-security-esp8266/\n    - OTA:  File > Examples > ArduinoOTA > BasicOTA\n*/\n\n#include <ESP8266WiFi.h>    // https://github.com/esp8266/Arduino (GNUv2.1 licence)\n#include <PubSubClient.h>   // https://github.com/knolleary/pubsubclient (no licence)\n#include <ArduinoOTA.h>\n\n#define DEBUG\n//#define TLS\n#define MQTT_VERSION MQTT_VERSION_3_1_1\n\n// Wi-Fi: Access Point SSID and password\nconst char*       AP_SSID           = \"[Redacted]\";\nconst char*       AP_PASSWORD       = \"[Redacted]\";\n\n// MQTT: client ID, broker IP address, port, username & password\nconst char*       MQTT_CLIENT_ID    = \"livingroom\";\nconst char*       MQTT_SERVER_IP    = \"192.168.1.10\";\n#ifdef TLS\nconst uint16_t    MQTT_SERVER_PORT  = 8883;\n#else\nconst uint16_t    MQTT_SERVER_PORT  = 1883;\n#endif\nconst char*       MQTT_USERNAME     = \"livingroom\";\nconst char*       MQTT_PASSWORD     = \"[Redacted]\";\n\n// MQTT: topics\n// lamp 3\nconst char*       TOPIC_LIGHT1_STATUS             = \"livingroom/light1/status\";\nconst char*       TOPIC_LIGHT1_BRIGHTNESS_STATUS  = \"livingroom/light1/brightness/status\";\nconst char*       TOPIC_LIGHT1_COLOR_STATUS       = \"livingroom/light1/color/status\";\nconst char*       TOPIC_LIGHT1_COMMAND            = \"livingroom/light1/switch\";\nconst char*       TOPIC_LIGHT1_BRIGHTNESS_COMMAND = \"livingroom/light1/brightness/set\";\nconst char*       TOPIC_LIGHT1_COLOR_COMMAND      = \"livingroom/light1/color/set\";\n// lamp 4\nconst char*       TOPIC_LIGHT2_STATUS             = \"livingroom/light2/status\";\nconst char*       TOPIC_LIGHT2_COMMAND            = \"livingroom/light2/switch\";\n// brightness sensor\nconst char*       TOPIC_TV_BRIGHTNESS_STATUS      = \"livingroom/tv/status\";\n\n// MQTT: payloads\n// Lamps 3 & 4: \"ON\"/\"OFF\"\nconst char*       PAYLOAD_ON            = \"ON\";\nconst char*       PAYLOAD_OFF           = \"OFF\";\n\nboolean           g_light1_status       = false; // turn off by default\nuint8_t           g_light1_brightness   = 255; // max value by default\nuint8_t           g_light1_color_red    = 255;\nuint8_t           g_light1_color_green  = 255;\nuint8_t           g_light1_color_blue   = 255;\nboolean           g_light2_status       = false;\nuint16_t          g_photocell_value     = 0;\nboolean           g_photocell_status    = false; // the TV is off\nuint32_t          g_photocell_last_change = 0;\nboolean           g_photocell_status_to_publish = false;\n\n// TV\nconst uint16_t    PHOTOCELL_THRESHOLD   = 150;\nconst uint16_t    PHOTOCELL_TIME_OFFSET = 3000; // 3 secondes in the same state before a notification to the controller\n\n// buffer used to send/receive data with MQTT\nconst uint8_t     MSG_BUFFER_SIZE       = 20;\nchar              g_msg_buffer[MSG_BUFFER_SIZE];\n\nconst uint8_t     LIGHT1_RED_PIN        = D3;\nconst uint8_t     LIGHT1_GREEN_PIN      = D2;\nconst uint8_t     LIGHT1_BLUE_PIN       = D1;\nconst uint8_t     LIGHT2_PIN            = D5; // D4 seems to be also connected to a internal LED...\nconst uint8_t     PHOTOCELL_PIN         = A0;\n\n// TLS: The fingerprint of the MQTT broker certificate (SHA1)\n#ifdef TLS\n// openssl x509 -fingerprint -in  <certificate>.crt\nconst char*       CA_FINGERPRINT    = \"[Redacted]\";\n// openssl x509 -subject -in  <certificate>.crt\nconst char*       CA_SUBJECT        = \"[Redacted]\";\n#endif\n\n// Fixed IP address: IP address, IP gateway, subnet, dns\nconst IPAddress   IP                (192, 168,   1, 101);\nconst IPAddress   IP_GATEWAY        (192, 168,   1,   1);\nconst IPAddress   IP_SUBNET         (255, 255, 255,   0);\nconst IPAddress   IP_DNS            (192, 168,   1,   1);\n\n// OTA: Hostname (MQTT_CLIENT_ID) & password\nconst char*       OTA_PASSWORD      = \"[Redacted]\";\n\n// WiFiFlientSecure instead of WiFiClient, for SSL/TLS support\n#ifdef TLS\nWiFiClientSecure  g_wifiClient;\n#else\nWiFiClient  g_wifiClient;\n#endif\nPubSubClient      g_mqttClient(g_wifiClient);\n\n///////////////////////////////////////////////////////////////////////////\n//\n// LIGHT 1 (RGB)\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to publish the status of the light 1\n*/\nvoid publishLight1Status() {\n  if (g_light1_status) {\n    if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT1_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT1_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n/*\n  Function called to publish the brightness status of the light 1\n*/\nvoid publishLight1BrightnessStatus() {\n  snprintf(g_msg_buffer, MSG_BUFFER_SIZE, \"%d\", g_light1_brightness);\n  if (g_mqttClient.publish(TOPIC_LIGHT1_BRIGHTNESS_STATUS, g_msg_buffer, true)) {\n#ifdef DEBUG\n    Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n    Serial.print(TOPIC_LIGHT1_BRIGHTNESS_STATUS);\n    Serial.print(F(\". Payload: \"));\n    Serial.println(g_msg_buffer);\n#endif\n  } else {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n  }\n}\n\n/*\n  Function called to publish the color status of the light 1\n*/\nvoid publishLight1ColorStatus() {\n  snprintf(g_msg_buffer, MSG_BUFFER_SIZE, \"%d,%d,%d\", g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n  if (g_mqttClient.publish(TOPIC_LIGHT1_COLOR_STATUS, g_msg_buffer, true)) {\n#ifdef DEBUG\n    Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n    Serial.print(TOPIC_LIGHT1_COLOR_STATUS);\n    Serial.print(F(\". Payload: \"));\n    Serial.println(g_msg_buffer);\n#endif\n  } else {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n  }\n}\n\n/*\n  Function called to set the color of the light 1\n  @param p_light1_color_red   The value for the red channel\n  @param p_light1_color_green The value for the green channel\n  @param p_light1_color_blue  The value for the blue channel\n*/\n\nvoid setLight1Color(uint8_t p_light1_color_red, uint8_t p_light1_color_green, uint8_t p_light1_color_blue) {\n  analogWrite(LIGHT1_RED_PIN,   map(p_light1_color_red,   0, 255, 0, g_light1_brightness));\n  analogWrite(LIGHT1_GREEN_PIN, map(p_light1_color_green, 0, 255, 0, g_light1_brightness));\n  analogWrite(LIGHT1_BLUE_PIN,  map(p_light1_color_blue,  0, 255, 0, g_light1_brightness));\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// LIGHT 2\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to publish the status of the light 2\n*/\nvoid publishLight2Status() {\n  if (g_light2_status) {\n    if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT2_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_LIGHT2_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n/*\n  Function called to switch the status of the light 2\n*/\nvoid setLight2Status() {\n  if (g_light2_status) {\n    digitalWrite(LIGHT2_PIN, HIGH);\n  } else {\n    digitalWrite(LIGHT2_PIN, LOW);\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// TV BRIGHTNESS SENSOR\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n  Function called to read the photocell attached to the TV\n */\nvoid readTVBrightness() {\n  // read the value from the photocell\n  g_photocell_value = analogRead(PHOTOCELL_PIN);\n\n  if (g_photocell_value > PHOTOCELL_THRESHOLD) {\n    // if the TV was alread switched on...\n    if (g_photocell_status) {\n      // test if it was switched on for the specified duration\n      if (millis() > g_photocell_last_change + PHOTOCELL_TIME_OFFSET) {\n        if (g_photocell_status_to_publish) {\n          g_photocell_status_to_publish = false;\n          publishTVStatus();\n        }\n      }\n    } else {\n      g_photocell_last_change = millis();\n      g_photocell_status = true;\n      g_photocell_status_to_publish = true;\n    }\n  } else {\n    if (g_photocell_status) {\n      g_photocell_last_change = millis();\n      g_photocell_status = false;\n      g_photocell_status_to_publish = true;\n    } else {\n      if (millis() > g_photocell_last_change + PHOTOCELL_TIME_OFFSET) {\n        if (g_photocell_status_to_publish) {\n          g_photocell_status_to_publish = false;\n          publishTVStatus();\n        }\n      }\n    }\n  }\n\n#ifdef DEBUG\n  Serial.print(F(\"INFO: Photocell read value: \"));\n  Serial.println(g_photocell_value);\n#endif\n}\n\n/*\n  Function called to publish the status of the TV\n*/\nvoid publishTVStatus() {\n    if (g_photocell_status) {\n    if (g_mqttClient.publish(TOPIC_TV_BRIGHTNESS_STATUS, PAYLOAD_ON, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_TV_BRIGHTNESS_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_ON);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  } else {\n    if (g_mqttClient.publish(TOPIC_TV_BRIGHTNESS_STATUS, PAYLOAD_OFF, true)) {\n#ifdef DEBUG\n      Serial.print(F(\"INFO: MQTT message publish succeeded. Topic: \"));\n      Serial.print(TOPIC_TV_BRIGHTNESS_STATUS);\n      Serial.print(F(\". Payload: \"));\n      Serial.println(PAYLOAD_OFF);\n#endif\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: MQTT message publish failed, either connection lost, or message too large\"));\n#endif\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// WIFI and TLS\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called to setup the connection to the Wi-Fi Access Point\n*/\nvoid setupWifi() {\n  delay(10);\n  // attempt to connect to the Wi-Fi AP\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(AP_SSID, AP_PASSWORD);\n  // define the fixed IP address\n  WiFi.config(IP, IP_GATEWAY, IP_SUBNET, IP_DNS);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n  }\n\n#ifdef DEBUG\n  Serial.println(F(\"INFO: Client is now connected to the Wi-Fi AP\"));\n  Serial.print(F(\"INFO: IP address: \"));\n  Serial.println(WiFi.localIP());\n#endif\n\n#ifdef TLS\n  verifyFingerprint();\n#endif\n}\n\n/*\n   Function called to verify the fingerprint of the MQTT server and establish a secure connection\n*/\n#ifdef TLS\nvoid verifyFingerprint() {\n  if (!g_wifiClient.connect(MQTT_SERVER_IP, MQTT_SERVER_PORT)) {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: The connection failed to the secure MQTT server\"));\n#endif\n    return;\n  }\n\n  if (g_wifiClient.verify(CA_FINGERPRINT, CA_SUBJECT)) {\n#ifdef DEBUG\n    Serial.println(F(\"INFO: The connection is secure\"));\n#endif\n  } else {\n#ifdef DEBUG\n    Serial.println(F(\"ERROR: The given certificate does't match\"));\n#endif\n  }\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////\n//\n// MQTT\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called when a MQTT message arrived\n   @param p_topic   The topic of the MQTT message\n   @param p_payload The payload of the MQTT message\n   @param p_length  The length of the payload\n*/\nvoid callback(char* p_topic, byte* p_payload, unsigned int p_length) {\n#ifdef DEBUG\n  Serial.println(F(\"INFO: A new MQTT message arrived\"));\n  Serial.print(F(\"INFO: Topic: \"));\n  Serial.println(p_topic);\n  Serial.print(F(\"INFO: Payload: \"));\n  for (int i = 0; i < p_length; i++) {\n    Serial.print((char)p_payload[i]);\n  }\n  Serial.println();\n  Serial.print(F(\"INFO: Length: \"));\n  Serial.println(p_length);\n#endif\n  // handle the MQTT topic of the received message\n  if (String(TOPIC_LIGHT1_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    if (payload.equals(String(PAYLOAD_ON))) {\n      if (g_light1_status != true) {\n        g_light1_status = true;\n        setLight1Color(g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n        publishLight1Status();\n      }\n    } else if (payload.equals(String(PAYLOAD_OFF))) {\n      if (g_light1_status != false) {\n        g_light1_status = false;\n        setLight1Color(LOW, LOW, LOW); // switch off the light\n        publishLight1Status();\n      }\n    }\n  } else if (String(TOPIC_LIGHT1_BRIGHTNESS_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    uint8_t brightness = payload.toInt();\n    if (brightness < 0 || brightness > 255) {\n      // do nothing...\n      return;\n    } else {\n      g_light1_brightness = brightness;\n      setLight1Color(g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n      publishLight1BrightnessStatus();\n    }\n  } else if (String(TOPIC_LIGHT1_COLOR_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    // get the position of the first and second comma\n    uint8_t firstIndex = payload.indexOf(',');\n    uint8_t lastIndex = payload.lastIndexOf(',');\n\n    // get the value for the red color\n    uint8_t red_color = payload.substring(0, firstIndex).toInt();\n    if (red_color < 0 || red_color > 255) {\n      return;\n    } else {\n      g_light1_color_red = red_color;\n    }\n    \n    // get the value for the green color\n    uint8_t green_color = payload.substring(firstIndex + 1, lastIndex).toInt();\n    if (green_color < 0 || green_color > 255) {\n      return;\n    } else {\n      g_light1_color_green = green_color;\n    }\n    \n    // get the value for the blue color\n    uint8_t blue_color = payload.substring(lastIndex + 1).toInt();\n    if (blue_color < 0 || blue_color > 255) {\n      return;\n    } else {\n      g_light1_color_blue = blue_color;\n    }\n\n    setLight1Color(g_light1_color_red, g_light1_color_green, g_light1_color_blue);\n    publishLight1ColorStatus();\n  } else if (String(TOPIC_LIGHT2_COMMAND).equals(p_topic)) {\n    // concat the payload into a string\n    String payload;\n    for (uint8_t i = 0; i < p_length; i++) {\n      payload.concat((char)p_payload[i]);\n    }\n    if (payload.equals(String(PAYLOAD_ON))) {\n      g_light2_status = true;\n      setLight2Status();\n      publishLight2Status();\n    } else if (payload.equals(String(PAYLOAD_OFF))) {\n      g_light2_status = false;\n      setLight2Status();\n      publishLight2Status();\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: The payload of the MQTT message is not valid\"));\n#endif\n    }\n  } else {\n    // do nothing.....\n#ifdef DEBUG\n    Serial.println(F(\"INFO: The received MQTT message was not used\"));\n#endif\n  }\n}\n\n/*\n   Function called to reconnect the client to the MQTT broker and publish/subscribe to/from some MQTT topics\n*/\nvoid reconnect() {\n  while (!g_mqttClient.connected()) {\n    if (g_mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {\n#ifdef DEBUG\n      Serial.println(F(\"INFO: The client is successfully connected to the MQTT broker\"));\n#endif\n      // subscribe to the light1 command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT1_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COMMAND);\n#endif\n      }\n\n      // subscribe to the light1 brightness command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT1_BRIGHTNESS_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_BRIGHTNESS_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_BRIGHTNESS_COMMAND);\n#endif\n      }\n\n      // subscribe to the light1 brightness command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT1_COLOR_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COLOR_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT1_COLOR_COMMAND);\n#endif\n      }\n\n      // subscribe to the light2 command topic\n      if (g_mqttClient.subscribe(TOPIC_LIGHT2_COMMAND)) {\n#ifdef DEBUG\n        Serial.print(F(\"INFO: Sending the MQTT subscribe succeeded. Topic: \"));\n        Serial.println(TOPIC_LIGHT2_COMMAND);\n#endif\n      } else {\n#ifdef DEBUG\n        Serial.print(F(\"ERROR: Sending the MQTT subscribe failed. Topic: \"));\n        Serial.println(TOPIC_LIGHT2_COMMAND);\n#endif\n      }\n\n      // set the initial status of lights 1 & 2\n      setLight1Color(LOW, LOW, LOW);\n      setLight2Status();\n\n      // publish the initial status of lights 1 & 2\n      publishLight1Status();\n      publishLight1BrightnessStatus();\n      publishLight1ColorStatus();\n      publishLight2Status();\n      publishTVStatus();\n    } else {\n#ifdef DEBUG\n      Serial.println(F(\"ERROR: The connection failed with the MQTT broker\"));\n      Serial.print(\"ERROR: rc: \");\n      Serial.println(g_mqttClient.state());\n      // wait 5 seconds before retrying\n      delay(5000);\n#endif\n    }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n// SETUP and LOOP\n//\n///////////////////////////////////////////////////////////////////////////\n\n/*\n   Function called once to initialize the board\n*/\nvoid setup() {\n#ifdef DEBUG\n  Serial.begin(115200);\n  Serial.println(F(\"\\nINFO: The Wi-Fi module is starting...\"));\n#endif\n\n  // init the LEDs as output, the TV brightness sensor as input\n  pinMode(LIGHT1_RED_PIN,     OUTPUT);\n  pinMode(LIGHT1_GREEN_PIN,   OUTPUT);\n  pinMode(LIGHT1_BLUE_PIN,    OUTPUT);\n  pinMode(LIGHT2_PIN,         OUTPUT);\n  pinMode(PHOTOCELL_PIN,      INPUT);\n\n  setupWifi();\n\n  // set the MQTT broker IP address and port\n  g_mqttClient.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);\n  // set the MQTT callback function\n  g_mqttClient.setCallback(callback);\n\n  // set the hostname & password for OTA\n  ArduinoOTA.setHostname(MQTT_CLIENT_ID);\n  ArduinoOTA.setPassword(OTA_PASSWORD);\n\n#ifdef DEBUG\n  ArduinoOTA.onStart([]() {\n    Serial.println(F(\"INFO: OTA starts\"));\n  });\n  ArduinoOTA.onEnd([]() {\n    Serial.println(F(\"INFO: OTA ends\"));\n  });\n  ArduinoOTA.onError([](ota_error_t error) {\n    Serial.println(F(\"INFO: An error occurs during OTA\"));\n  });\n#endif\n  ArduinoOTA.begin();\n\n  // blink the internal LED to indicate the end of the startup\n  pinMode(BUILTIN_LED, OUTPUT);\n  digitalWrite(BUILTIN_LED, LOW);\n  delay(100);\n  digitalWrite(BUILTIN_LED, HIGH);\n  delay(100);\n  digitalWrite(BUILTIN_LED, LOW);\n  delay(100);\n  digitalWrite(BUILTIN_LED, HIGH);\n}\n\n/*\n   Function called infinitely after the setup function\n*/\nvoid loop() {\n  // keep the MQTT client connected to the broker\n  if (!g_mqttClient.connected()) {\n    reconnect();\n  }\n  g_mqttClient.loop();\n  \n  // a delay is necessary if the debug is disabled\n  // without a delay, there is some latency to switch on/off a light\n  yield();\n  //delay(100); \n  \n  readTVBrightness();\n\n  yield();\n\n  ArduinoOTA.handle();\n\n  yield();\n}\n"
  }
]