Browse Source

Fix HA autodicovery, allow to report color as comma separated values

fastled
Xose Pérez 7 years ago
parent
commit
cfb9880d9b
9 changed files with 3704 additions and 3634 deletions
  1. +1
    -0
      code/espurna/config/general.h
  2. BIN
      code/espurna/data/index.html.gz
  3. +39
    -31
      code/espurna/homeassitant.ino
  4. +29
    -3
      code/espurna/light.ino
  5. +3599
    -3589
      code/espurna/static/index.html.gz.h
  6. +9
    -2
      code/espurna/web.ino
  7. +2
    -1
      code/html/custom.css
  8. +5
    -2
      code/html/custom.js
  9. +20
    -6
      code/html/index.html

+ 1
- 0
code/espurna/config/general.h View File

@ -498,6 +498,7 @@ PROGMEM const char* const custom_reset_string[] = {
#define LIGHT_USE_COLOR 1 // Use 3 first channels as RGB #define LIGHT_USE_COLOR 1 // Use 3 first channels as RGB
#define LIGHT_USE_WHITE 0 // Use white channel whenever RGB have the same value #define LIGHT_USE_WHITE 0 // Use white channel whenever RGB have the same value
#define LIGHT_USE_GAMMA 0 // Use gamma correction for color channels #define LIGHT_USE_GAMMA 0 // Use gamma correction for color channels
#define LIGHT_USE_CSS 1 // Use CSS style to report colors (1=> "#FF0000", 0=> "255,0,0")
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// POWER METERING // POWER METERING


BIN
code/espurna/data/index.html.gz View File


+ 39
- 31
code/espurna/homeassitant.ino View File

@ -10,49 +10,57 @@ Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
#include <ArduinoJson.h> #include <ArduinoJson.h>
void haSend() {
void haSend(bool add) {
DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n")); DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n"));
String component = String("light");
String output;
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
if (add) {
root["name"] = getSetting("hostname");
root["platform"] = "mqtt";
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
if (relayCount()) {
root["state_topic"] = getTopic(MQTT_TOPIC_RELAY, 0, false);
root["command_topic"] = getTopic(MQTT_TOPIC_RELAY, 0, true);
}
root["name"] = getSetting("hostname");
root["platform"] = "mqtt";
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
if (lightHasColor()) {
root["brightness"] = 1;
root["brightness_state_topic"] = getTopic(MQTT_TOPIC_BRIGHTNESS, false);
root["brightness_command_topic"] = getTopic(MQTT_TOPIC_BRIGHTNESS, true);
root["rgb"] = 1;
root["rgb_state_topic"] = getTopic(MQTT_TOPIC_COLOR, false);
root["rgb_command_topic"] = getTopic(MQTT_TOPIC_COLOR, true);
root["color_temp"] = 1;
root["color_temp_command_topic"] = getTopic(MQTT_TOPIC_MIRED, true);
if (relayCount()) {
root["state_topic"] = getTopic(MQTT_TOPIC_RELAY, 0, false);
root["command_topic"] = getTopic(MQTT_TOPIC_RELAY, 0, true);
root["payload_on"] = String("1");
root["payload_off"] = String("0");
} }
if (lightChannels() > 3) {
root["white_value"] = 1;
root["white_value_state_topic"] = getTopic(MQTT_TOPIC_CHANNEL, 3, false);
root["white_value_command_topic"] = getTopic(MQTT_TOPIC_CHANNEL, 3, true);
}
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
#endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
if (lightHasColor()) {
root["brightness_state_topic"] = getTopic(MQTT_TOPIC_BRIGHTNESS, false);
root["brightness_command_topic"] = getTopic(MQTT_TOPIC_BRIGHTNESS, true);
root["rgb_state_topic"] = getTopic(MQTT_TOPIC_COLOR, false);
root["rgb_command_topic"] = getTopic(MQTT_TOPIC_COLOR, true);
root["color_temp_command_topic"] = getTopic(MQTT_TOPIC_MIRED, true);
}
String output;
root.printTo(output);
if (lightChannels() > 3) {
root["white_value_state_topic"] = getTopic(MQTT_TOPIC_CHANNEL, 3, false);
root["white_value_command_topic"] = getTopic(MQTT_TOPIC_CHANNEL, 3, true);
}
#endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
root.printTo(output);
}
#if LIGHT_PROVIDER == LIGHT_PROVIDER_NONE
String component = String("switch");
#else
String component = String("light");
#endif
String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX)
+ String("/") + component + "/" + getSetting("hostname");
String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) +
"/" + component +
"/" + getSetting("hostname") +
"/config";
mqttSendRaw(topic.c_str(), output.c_str()); mqttSendRaw(topic.c_str(), output.c_str());


+ 29
- 3
code/espurna/light.ino View File

@ -142,6 +142,24 @@ void _toRGB(char * rgb, size_t len) {
_toRGB(rgb, len, false); _toRGB(rgb, len, false);
} }
void _toLong(char * color, size_t len, bool applyBrightness) {
if (!lightHasColor()) return;
float b = applyBrightness ? (float) _brightness / LIGHT_MAX_BRIGHTNESS : 1;
snprintf_P(color, len, PSTR("%d,%d,%d"),
(int) (_channels[0].value * b),
(int) (_channels[1].value * b),
(int) (_channels[2].value * b)
);
}
void _toLong(char * color, size_t len) {
_toLong(color, len, false);
}
// Thanks to Sacha Telgenhof for sharing this code in his AiLight library // Thanks to Sacha Telgenhof for sharing this code in his AiLight library
// https://github.com/stelgenhof/AiLight // https://github.com/stelgenhof/AiLight
void _fromKelvin(unsigned long kelvin) { void _fromKelvin(unsigned long kelvin) {
@ -367,12 +385,16 @@ unsigned char lightWhiteChannels() {
void lightMQTT() { void lightMQTT() {
char buffer[8];
char buffer[12];
if (lightHasColor()) { if (lightHasColor()) {
// Color // Color
_toRGB(buffer, 8, false);
if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) {
_toRGB(buffer, 12, false);
} else {
_toLong(buffer, 12, false);
}
mqttSend(MQTT_TOPIC_COLOR, buffer); mqttSend(MQTT_TOPIC_COLOR, buffer);
// Brightness // Brightness
@ -484,7 +506,11 @@ void _lightAPISetup() {
apiRegister(MQTT_TOPIC_COLOR, MQTT_TOPIC_COLOR, apiRegister(MQTT_TOPIC_COLOR, MQTT_TOPIC_COLOR,
[](char * buffer, size_t len) { [](char * buffer, size_t len) {
_toRGB(buffer, len, false);
if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) {
_toRGB(buffer, len, false);
} else {
_toLong(buffer, len, false);
}
}, },
[](const char * payload) { [](const char * payload) {
lightColor(payload); lightColor(payload);


+ 3599
- 3589
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 9
- 2
code/espurna/web.ino View File

@ -176,10 +176,16 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
} }
#if HOMEASSISTANT_SUPPORT #if HOMEASSISTANT_SUPPORT
if (action.equals("ha_send") && root.containsKey("data")) {
if (action.equals("ha_add") && root.containsKey("data")) {
String value = root["data"]; String value = root["data"];
setSetting("haPrefix", value); setSetting("haPrefix", value);
haSend();
haSend(true);
wsSend_P(client_id, PSTR("{\"message\": 6}"));
}
if (action.equals("ha_del") && root.containsKey("data")) {
String value = root["data"];
setSetting("haPrefix", value);
haSend(false);
wsSend_P(client_id, PSTR("{\"message\": 6}")); wsSend_P(client_id, PSTR("{\"message\": 6}"));
} }
#endif #endif
@ -524,6 +530,7 @@ void _wsStart(uint32_t client_id) {
root["useColor"] = getSetting("useColor", LIGHT_USE_COLOR).toInt() == 1; root["useColor"] = getSetting("useColor", LIGHT_USE_COLOR).toInt() == 1;
root["useWhite"] = getSetting("useWhite", LIGHT_USE_WHITE).toInt() == 1; root["useWhite"] = getSetting("useWhite", LIGHT_USE_WHITE).toInt() == 1;
root["useGamma"] = getSetting("useGamma", LIGHT_USE_GAMMA).toInt() == 1; root["useGamma"] = getSetting("useGamma", LIGHT_USE_GAMMA).toInt() == 1;
root["useCSS"] = getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1;
if (lightHasColor()) { if (lightHasColor()) {
#ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR #ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR


+ 2
- 1
code/html/custom.css View File

@ -47,6 +47,7 @@
} }
.button-reset, .button-reset,
.button-reconnect, .button-reconnect,
.button-ha-del,
.button-rfb-forget { .button-rfb-forget {
background: rgb(202, 60, 60); background: rgb(202, 60, 60);
} }
@ -55,7 +56,7 @@
margin-left: 5px; margin-left: 5px;
} }
.button-upgrade-browse, .button-upgrade-browse,
.button-ha-send,
.button-ha-add,
.button-apikey { .button-apikey {
background: rgb(0, 202, 0); background: rgb(0, 202, 0);
margin-left: 5px; margin-left: 5px;


+ 5
- 2
code/html/custom.js View File

@ -952,8 +952,11 @@ function init() {
$(".button-add-network").on('click', function() { $(".button-add-network").on('click', function() {
$("div.more", addNetwork()).toggle(); $("div.more", addNetwork()).toggle();
}); });
$(".button-ha-send").on('click', function() {
websock.send(JSON.stringify({'action': 'ha_send', 'data': $("input[name='haPrefix']").val()}));
$(".button-ha-add").on('click', function() {
websock.send(JSON.stringify({'action': 'ha_add', 'data': $("input[name='haPrefix']").val()}));
});
$(".button-ha-del").on('click', function() {
websock.send(JSON.stringify({'action': 'ha_del', 'data': $("input[name='haPrefix']").val()}));
}); });
$(document).on('change', 'input', hasChanged); $(document).on('change', 'input', hasChanged);


+ 20
- 6
code/html/index.html View File

@ -391,23 +391,37 @@
<div class="pure-u-1 pure-u-md-3-4 hint">Use gamma correction for RGB channels.<br />Will only work if "use colorpicker" above is also ON.</div> <div class="pure-u-1 pure-u-md-3-4 hint">Use gamma correction for RGB channels.<br />Will only work if "use colorpicker" above is also ON.</div>
</div> </div>
<div class="pure-g module module-color">
<div class="pure-u-1 pure-u-sm-1-4"><label for="useCSS">Use CSS style</label></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="useCSS" tabindex="11" /></div>
<div class="pure-u-0 pure-u-md-1-2">&nbsp;</div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">Use CSS style to report colors to MQTT and REST API. <br />Red will be reported as "#FF0000" if ON, otherwise "255,0,0"</div>
</div>
<div class="pure-g module module-alexa"> <div class="pure-g module module-alexa">
<div class="pure-u-1 pure-u-sm-1-4"><label for="alexaEnabled">Alexa integration</label></div> <div class="pure-u-1 pure-u-sm-1-4"><label for="alexaEnabled">Alexa integration</label></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="alexaEnabled" tabindex="11" /></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="alexaEnabled" tabindex="12" /></div>
</div> </div>
<div class="pure-g module module-ha"> <div class="pure-g module module-ha">
<label class="pure-u-1 pure-u-md-1-4" for="haPrefix">Home Assistant Prefix</label> <label class="pure-u-1 pure-u-md-1-4" for="haPrefix">Home Assistant Prefix</label>
<input class="pure-u-1 pure-u-md-1-2" name="haPrefix" type="text" tabindex="31" />
<div class="pure-u-1-3 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-ha-send">Send</button></div>
<input class="pure-u-1 pure-u-md-1-4" name="haPrefix" type="text" tabindex="13" />
<div class="pure-u-1-2 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-ha-add">Add</button></div>
<div class="pure-u-1-2 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-ha-del">Delete</button></div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">Home Assistant auto-discovery feature.</div>
<div class="pure-u-1 pure-u-md-3-4 hint">
Home Assistant auto-discovery feature.<br />
Add should immediately add the device to your HA console. Messages are retained so the device should be there even after a HA reboot<br />
To remove the device click on the Del button (retained message will be deleted) and reboot HA.
</div>
</div> </div>
<div class="pure-g module module-ds module-dht"> <div class="pure-g module module-ds module-dht">
<label class="pure-u-1 pure-u-sm-1-4" for="tmpUnits">Temperature units</label> <label class="pure-u-1 pure-u-sm-1-4" for="tmpUnits">Temperature units</label>
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="12" value="0"> Celsius (&deg;C)</input></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="13" value="1"> Fahrenheit (&deg;F)</input></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="14" value="0"> Celsius (&deg;C)</input></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="15" value="1"> Fahrenheit (&deg;F)</input></div>
</div> </div>
</fieldset> </fieldset>


Loading…
Cancel
Save