3.9.16 20170214
* Update latching relay handler
* Add support for IR led using IRremoteESP8266 library (#59)
* Add Hue argument passing using ArduinoJSON library (#59)
This commit is contained in:
arendst 2017-02-14 14:27:08 +01:00
parent 533855c210
commit 381bb4b50c
11 changed files with 146 additions and 36 deletions

View File

@ -1,7 +1,7 @@
## Sonoff-Tasmota
Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE.
Current version is **3.9.15** - See ```sonoff/_releasenotes.ino``` for change information.
Current version is **3.9.16** - See ```sonoff/_releasenotes.ino``` for change information.
- This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic.
- Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.

Binary file not shown.

View File

@ -19,4 +19,4 @@ board = esp01_1m
; board = esp8285
build_flags = -Wl,-Tesp8266.flash.1m64.ld -DMQTT_MAX_PACKET_SIZE=400
lib_deps = PubSubClient, NeoPixelBus
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON

View File

@ -1,4 +1,9 @@
/* 3.9.15 20170213
/* 3.9.16 20170214
* Update latching relay handler
* Add support for IR led using IRremoteESP8266 library (#59)
* Add Hue argument passing using ArduinoJSON library (#59)
*
* 3.9.15 20170213
* Change JSON float values from string to number according to http://json.org (#56)
* Add support for exs latched relay module https://ex-store.de/ESP8266-WiFi-Relay-V31 (#58)
* Add support for inverted relays

View File

@ -10,7 +10,7 @@
* ====================================================
*/
#define VERSION 0x03090F00 // 3.9.15
#define VERSION 0x03091000 // 3.9.16
//#define BE_MINIMAL // Compile a minimal version if upgrade memory gets tight (still 404k)
// To be used as step 1. Next step is compile and use desired version
@ -56,6 +56,9 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#ifdef USE_DOMOTICZ
#undef USE_DOMOTICZ // Disable Domoticz
#endif
//#ifdef USE_WEBSERVER
//#undef USE_WEBSERVER // Disable Webserver
//#endif
#ifdef USE_EMULATION
#undef USE_EMULATION // Disable Wemo or Hue emulation
#endif
@ -74,6 +77,9 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#ifdef USE_DHT
#undef USE_DHT // Disable internal DHT sensor
#endif
#ifdef USE_IR_REMOTE
#undef USE_IR_REMOTE // Disable IR driver
#endif
#endif // BE_MINIMAL
#ifndef SWITCH_MODE
@ -148,6 +154,12 @@ enum butt_t {PRESSED, NOT_PRESSED};
#ifdef USE_I2C
#include <Wire.h> // I2C support library
#endif // USE_I2C
#if defined USE_EMULATION || defined USE_IR_REMOTE
#include <ArduinoJson.h>
const size_t bufferSize = JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(10) + 130; // Required size for complete HUE light JSON object or other JSON objects
DynamicJsonBuffer jsonBuffer(bufferSize);
#endif // USE_EMULATION || USE_IR_REMOTE
typedef void (*rtcCallback)();
@ -789,17 +801,16 @@ void getClient(char* output, const char* input, byte size)
void setLatchingRelay(uint8_t power, uint8_t state)
{
power &= 1;
if (state == 2) { // Init relay
if (state == 2) { // Reset relay
state = 0;
latching_power = power;
latching_relay_pulse = 0;
}
else if (state == 1) { // Set port power to On
else if (state && !latching_relay_pulse) { // Set port power to On
latching_power = power;
latching_relay_pulse = 2; // max 200mS (initiated by stateloop())
}
else { // Set saved port to Off
power = latching_power;
}
if (pin[GPIO_REL1 +power] < 99) digitalWrite(pin[GPIO_REL1 +power], rel_inverted[power] ? !state : state);
if (pin[GPIO_REL1 +latching_power] < 99) digitalWrite(pin[GPIO_REL1 +latching_power], rel_inverted[latching_power] ? !state : state);
}
void setRelay(uint8_t power)
@ -1743,6 +1754,11 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
// Serviced
}
#endif // USE_WS2812
#ifdef USE_IR_REMOTE
else if ((pin[GPIO_IRSEND] < 99) && ir_send_command(type, index, dataBufUc, data_len, payload, svalue, sizeof(svalue))) {
// Serviced
}
#endif // USE_IR_REMOTE
else {
type = NULL;
}
@ -1769,6 +1785,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
#endif // USE_I2C
#ifdef USE_WS2812
if (pin[GPIO_WS2812] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Pixels, Led, Color, Dimmer, Scheme, Fade, Speed, Width, Wakeup, LedTable"), svalue);
#endif
#ifdef USE_IR_REMOTE
if (pin[GPIO_IRSEND] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, IRSend"), svalue);
#endif
snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue);
mqtt_publish_topic_P(0, PSTR("COMMANDS3"), svalue);
@ -2540,6 +2559,10 @@ void GPIO_init()
#ifdef USE_WS2812
if (pin[GPIO_WS2812] < 99) ws2812_init();
#endif // USE_WS2812
#ifdef USE_IR_REMOTE
if (pin[GPIO_IRSEND] < 99) ir_send_init();
#endif // USE_IR_REMOTE
}
void setup()

View File

@ -12,11 +12,12 @@ enum upins_t {
GPIO_I2C_SCL, // I2C SCL
GPIO_I2C_SDA, // I2C SDA
GPIO_WS2812, // WS2812 Led string
GPIO_IRSEND, // IR remote
GPIO_SWT1, // User connected external switches
GPIO_SENSOR_END };
// Text in webpage Module Parameters and commands GPIOS and GPIO
const char sensors[GPIO_SENSOR_END][8] PROGMEM = {
const char sensors[GPIO_SENSOR_END][9] PROGMEM = {
"None",
"DHT11",
"AM2301",
@ -25,6 +26,7 @@ const char sensors[GPIO_SENSOR_END][8] PROGMEM = {
"I2C SCL",
"I2C SDA",
"WS2812",
"IRremote",
"Switch" };
// Programmer selectable GPIO functionality offset by user selectable GPIOs
@ -257,7 +259,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
{ "EXS Relay", // Latching relay https://ex-store.de/ESP8266-WiFi-Relay-V31
// Module Pin 1 VCC 3V3, Module Pin 6 GND
GPIO_KEY1, // GPIO00 Module Pin 8 - Button (firmware flash)
GPIO_USER, // GPIO01 Module Pin 2 = UART0_TXD
0, // GPIO01 Module Pin 2 = UART0_TXD
GPIO_USER, // GPIO02 Module Pin 7
GPIO_USER, // GPIO03 Module Pin 3 = UART0_RXD
GPIO_USER, // GPIO04 Module Pin 10

View File

@ -994,7 +994,7 @@ void addLog(byte loglevel, const char *line)
#endif // DEBUG_ESP_PORT
if (loglevel <= seriallog_level) Serial.printf("%s %s\n", mxtime, line);
#ifdef USE_WEBSERVER
if (loglevel <= sysCfg.weblog_level) {
if (sysCfg.webserver && (loglevel <= sysCfg.weblog_level)) {
Log[logidx] = String(mxtime) + " " + String(line);
logidx++;
if (logidx > MAX_LOG_LINES -1) logidx = 0;

View File

@ -77,7 +77,7 @@
#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional)
// -- HTTP ----------------------------------------
#define USE_WEBSERVER // Enable web server and wifi manager (+60k code, +4k mem) - Disable by //
#define USE_WEBSERVER // Enable web server and wifi manager (+62k code, +4k mem) - Disable by //
#define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa
#define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin)
#define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+11k code, +2k mem)
@ -124,6 +124,8 @@
#define USE_BMP // Add I2C code for BMP/BME280 sensor
#define USE_HTU // Add I2C code for HTU21 sensor
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0.3k mem)
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+8k code, +1k mem) - Disable by //
#define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB)
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial TXD) (+1k mem)

View File

@ -1497,6 +1497,7 @@ void hue_lights(String *path)
uint8_t device = 1;
int16_t pos = 0;
uint8_t bri = 0;
bool on = false;
char id[4];
path->remove(0,path->indexOf("/lights")); // Remove until /lights
@ -1539,29 +1540,22 @@ void hue_lights(String *path)
response.replace("{cmd}", "state/on");
if (webServer->args() == 1)
{
String json = webServer->arg(0);
json.replace(" ",""); // remove blanks
if (json.indexOf("\"on\":") >= 0) // Got "on" command
JsonObject &hue_json = jsonBuffer.parseObject(webServer->arg(0));
on = hue_json["on"];
switch(on)
{
if (json.indexOf("false") >= 0) // false -> turn device off
{
do_cmnd_power(device, 0);
response.replace("{res}", "false");
}
else if(json.indexOf("true") >= 0) // true -> Turn device on
{
do_cmnd_power(device, 1);
response.replace("{res}", "true");
}
else
{
response.replace("{res}", (power & (0x01 << (device-1))) ? "true" : "false");
}
case false : do_cmnd_power(device, 0);
response.replace("{res}", "false");
break;
case true : do_cmnd_power(device, 1);
response.replace("{res}", "true");
break;
default : response.replace("{res}", (power & (0x01 << (device-1))) ? "true" : "false");
break;
}
#ifdef USE_WS2812
if ((pin[GPIO_WS2812] < 99) && ((pos=json.indexOf("\"bri\":")) >= 0)) {
bri = atoi(json.substring(pos+6).c_str());
bri = hue_json["bri"];
if (pin[GPIO_WS2812] < 99) {
ws2812_changeBrightness(bri);
response += ",";
response += FPSTR(HUE_LIGHT_RESPONSE_JSON);
@ -1620,7 +1614,7 @@ void handle_hue_api(String *path)
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
if (path->endsWith("/invalid/")) {} // Just ignore
if (path->endsWith("/invalid/")) {} // Just ignore
else if (path->endsWith("/")) hue_auth(path); // New HUE App setup
else if (path->endsWith("/config")) hue_config(path);
else if (path->indexOf("/lights") >= 0) hue_lights(path);

84
sonoff/xdrv_ir_send.ino Normal file
View File

@ -0,0 +1,84 @@
/*
Copyright (c) 2017 Heiko Krupp and Theo Arends. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef USE_IR_REMOTE
/*********************************************************************************************\
* IR Remote send using IRremoteESP8266 library
\*********************************************************************************************/
#include <IRremoteESP8266.h>
IRsend *irsend = NULL;
void ir_send_init(void)
{
irsend = new IRsend(pin[GPIO_IRSEND]); // an IR led is at GPIO_IRSEND
irsend->begin();
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
boolean ir_send_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
{
boolean serviced = true;
boolean error = false;
const char *protocol;
uint8_t bits = 0;
uint32_t data = 0;
if (!strcmp(type,"IRSEND")) {
if (data_len) {
JsonObject &ir_json = jsonBuffer.parseObject(dataBuf);
if (!ir_json.success()) {
snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"Invalid JSON\"}")); // JSON decode failed
} else {
snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"Done\"}"));
protocol = ir_json["PROTOCOL"];
bits = ir_json["BITS"];
data = ir_json["DATA"];
if (protocol && bits && data) {
if (!strcmp(protocol,"NEC")) irsend->sendNEC(data, bits);
else if (!strcmp(protocol,"SONY")) irsend->sendSony(data, bits);
else if (!strcmp(protocol,"RC5")) irsend->sendRC5(data, bits);
else if (!strcmp(protocol,"RC6")) irsend->sendRC6(data, bits);
else if (!strcmp(protocol,"DISH")) irsend->sendDISH(data, bits);
else if (!strcmp(protocol,"JVC")) irsend->sendJVC(data, bits, 1);
else if (!strcmp(protocol,"SAMSUNG")) irsend->sendSAMSUNG(data, bits);
else {
snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"Protocol not supported\"}"));
}
} else error = true;
}
} else error = true;
if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"No protocol, bits or data\"}"));
}
else {
serviced = false; // Unknown command
}
return serviced;
}
#endif // USE_IR_REMOTE

View File

@ -579,7 +579,7 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_
snprintf_P(svalue, ssvalue, PSTR("{\"Scheme\":%d}"), sysCfg.ws_scheme);
}
else {
serviced = false;
serviced = false; // Unknown command
}
return serviced;
}