Browse Source

Merge branch 'dev' into feature/atlas-scientific-ph-probe

alexa
Xose Pérez 6 years ago
committed by GitHub
parent
commit
8eb7a1831b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 20771 additions and 18905 deletions
  1. +3
    -3
      README.md
  2. +3
    -5
      code/espurna/api.ino
  3. +3
    -0
      code/espurna/config/arduino.h
  4. +7
    -2
      code/espurna/config/general.h
  5. +73
    -2
      code/espurna/config/hardware.h
  6. +46
    -5
      code/espurna/config/sensors.h
  7. +1
    -1
      code/espurna/config/version.h
  8. BIN
      code/espurna/data/index.all.html.gz
  9. BIN
      code/espurna/data/index.light.html.gz
  10. BIN
      code/espurna/data/index.rfbridge.html.gz
  11. BIN
      code/espurna/data/index.rfm69.html.gz
  12. BIN
      code/espurna/data/index.sensor.html.gz
  13. BIN
      code/espurna/data/index.small.html.gz
  14. +5
    -1
      code/espurna/nofuss.ino
  15. +3
    -1
      code/espurna/relay.ino
  16. +18
    -0
      code/espurna/sensor.ino
  17. +42
    -1
      code/espurna/sensors/AnalogSensor.h
  18. +150
    -0
      code/espurna/sensors/MAX6675.h
  19. +14
    -2
      code/espurna/sensors/PulseMeterSensor.h
  20. +4
    -6
      code/espurna/settings.ino
  21. +3130
    -3118
      code/espurna/static/index.all.html.gz.h
  22. +2982
    -2973
      code/espurna/static/index.light.html.gz.h
  23. +2587
    -2578
      code/espurna/static/index.rfbridge.html.gz.h
  24. +4064
    -4055
      code/espurna/static/index.rfm69.html.gz.h
  25. +2641
    -2629
      code/espurna/static/index.sensor.html.gz.h
  26. +2543
    -2535
      code/espurna/static/index.small.html.gz.h
  27. +38
    -28
      code/espurna/telnet.ino
  28. +11
    -4
      code/espurna/thinkspeak.ino
  29. +3
    -0
      code/espurna/utils.ino
  30. +5
    -6
      code/gulpfile.js
  31. +50
    -13
      code/html/index.html
  32. +2292
    -931
      code/package-lock.json
  33. +2
    -5
      code/package.json
  34. +51
    -1
      code/platformio.ini
  35. BIN
      images/devices/lombex-lux-nova-flash-2.jpg
  36. BIN
      images/devices/lombex-lux-nova-flash.jpg
  37. BIN
      images/devices/lombex-lux-nova.jpg

+ 3
- 3
README.md View File

@ -3,10 +3,10 @@
ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smart switches, lights and sensors.
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
[![version](https://img.shields.io/badge/version-1.13.3-brightgreen.svg)](CHANGELOG.md)
[![branch](https://img.shields.io/badge/branch-sensors-orange.svg)](https://github.com/xoseperez/espurna/tree/sensors/)
[![version](https://img.shields.io/badge/version-1.13.4-DEV-brightgreen.svg)](CHANGELOG.md)
[![branch](https://img.shields.io/badge/branch-dev-orange.svg)](https://github.com/xoseperez/espurna/tree/dev/)
[![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=sensors)](https://travis-ci.org/xoseperez/espurna)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=dev)](https://travis-ci.org/xoseperez/espurna)
[![codacy](https://api.codacy.com/project/badge/Grade/c9496e25cf07434cba786b462cb15f49)](https://www.codacy.com/app/xoseperez/espurna/dashboard)
[![downloads](https://img.shields.io/github/downloads/xoseperez/espurna/total.svg)](https://github.com/xoseperez/espurna/releases)
<br />


+ 3
- 5
code/espurna/api.ino View File

@ -19,7 +19,6 @@ typedef struct {
api_put_callback_f putFn = NULL;
} web_api_t;
std::vector<web_api_t> _apis;
bool _api_restful = API_RESTFUL;
// -----------------------------------------------------------------------------
@ -32,14 +31,13 @@ void _apiWebSocketOnSend(JsonObject& root) {
root["apiEnabled"] = getSetting("apiEnabled", API_ENABLED).toInt() == 1;
root["apiKey"] = getSetting("apiKey");
root["apiRealTime"] = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
root["apiRestFul"] = _api_restful;
root["apiRestFul"] = getSetting("apiRestFul", API_RESTFUL).toInt() == 1;
}
void _apiConfigure() {
_api_restful = getSetting("apiRestFul", API_RESTFUL).toInt() == 1;
// Nothing to do
}
// -----------------------------------------------------------------------------
// API
// -----------------------------------------------------------------------------
@ -165,7 +163,7 @@ bool _apiRequestCallback(AsyncWebServerRequest *request) {
// Check if its a PUT
if (api.putFn != NULL) {
if (!_api_restful || (request->method() == HTTP_PUT)) {
if ((getSetting("apiRestFul", API_RESTFUL).toInt() != 1) || (request->method() == HTTP_PUT)) {
if (request->hasParam("value", request->method() == HTTP_PUT)) {
AsyncWebParameter* p = request->getParam("value", request->method() == HTTP_PUT);
(api.putFn)((p->value()).c_str());


+ 3
- 0
code/espurna/config/arduino.h View File

@ -36,6 +36,7 @@
//#define ITEAD_SONOFF_T1_2CH
//#define ITEAD_SONOFF_T1_3CH
//#define ITEAD_SONOFF_S31
//#define ORVIBO_B25
//#define YJZK_SWITCH_2CH
//#define ELECTRODRAGON_WIFI_IOT
//#define WORKCHOICE_ECOPLUG
@ -102,6 +103,8 @@
//#define IWOOLE_LED_TABLE_LAMP
//#define EXS_WIFI_RELAY_V50
//#define TECKIN_SP22_V14
//#define LOMBEX_LUX_NOVA2_TUNABLE_WHITE
//#define LOMBEX_LUX_NOVA2_WHITE_COLOR
//--------------------------------------------------------------------------------
// Features (values below are non-default values)


+ 7
- 2
code/espurna/config/general.h View File

@ -110,8 +110,8 @@
#define TELNET_STA 0 // By default, disallow connections via STA interface
#endif
#ifndef TELNET_PASSWORD
#define TELNET_PASSWORD 1 // Request password to start telnet session by default
#ifndef TELNET_AUTHENTICATION
#define TELNET_AUTHENTICATION 1 // Request password to start telnet session by default
#endif
#define TELNET_PORT 23 // Port to listen to telnet clients
@ -1005,6 +1005,11 @@
#define THINGSPEAK_APIKEY "" // Default API KEY
#endif
#ifndef THINGSPEAK_CLEAR_CACHE
#define THINGSPEAK_CLEAR_CACHE 1 // Clear cache after sending values
// Not clearing it will result in latest values for each field being sent every time
#endif
#define THINGSPEAK_USE_ASYNC 1 // Use AsyncClient instead of WiFiClientSecure
// THINGSPEAK OVER SSL


+ 73
- 2
code/espurna/config/hardware.h View File

@ -930,6 +930,31 @@
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
// -----------------------------------------------------------------------------
// ORVIBO
// -----------------------------------------------------------------------------
#elif defined(ORVIBO_B25)
// Info
#define MANUFACTURER "ORVIBO"
#define DEVICE "B25"
// Buttons
#define BUTTON1_PIN 14
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1
// Relays
#define RELAY1_PIN 5
#define RELAY1_TYPE RELAY_TYPE_NORMAL
// LEDs
#define LED1_PIN 12 // 4 blue led
#define LED1_PIN_INVERSE 1
#define LED2_PIN 4 // 12 red led
#define LED2_PIN_INVERSE 1
// -----------------------------------------------------------------------------
// YJZK
// -----------------------------------------------------------------------------
@ -2957,6 +2982,53 @@
#define LIGHT_CH3_INVERSE 0
#define LIGHT_CH4_INVERSE 0
// -----------------------------------------------------------------------------
// Lombex Lux Nova 2 Tunable White
// https://www.amazon.com/Lombex-Compatible-Equivalent-Dimmable-2700K-6500K/dp/B07B8K72PR
// -----------------------------------------------------------------------------
#elif defined(LOMBEX_LUX_NOVA2_TUNABLE_WHITE)
// Info
#define MANUFACTURER "LOMBEX"
#define DEVICE "LUX_NOVA2_TUNABLE_WHITE"
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX
#define DUMMY_RELAY_COUNT 1
// Light
#define LIGHT_CHANNELS 5
#define MY92XX_MODEL MY92XX_MODEL_MY9291
#define MY92XX_CHIPS 1
#define MY92XX_DI_PIN 4
#define MY92XX_DCKI_PIN 5
#define MY92XX_COMMAND MY92XX_COMMAND_DEFAULT
// No RGB on this bulb. Warm white on channel 0, cool white on channel 3
#define MY92XX_MAPPING 255, 255, 255, 3, 0
// -----------------------------------------------------------------------------
// Lombex Lux Nova 2 White and Color
// https://www.amazon.com/Lombex-Compatible-Equivalent-Dimmable-2700K-6500K/dp/B07B8K72PR
// -----------------------------------------------------------------------------
#elif defined(LOMBEX_LUX_NOVA2_WHITE_COLOR)
// Info
#define MANUFACTURER "LOMBEX"
#define DEVICE "LUX_NOVA2_WHITE_COLOR"
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX
#define DUMMY_RELAY_COUNT 1
// Light
#define LIGHT_CHANNELS 4
#define MY92XX_MODEL MY92XX_MODEL_MY9291
#define MY92XX_CHIPS 1
#define MY92XX_DI_PIN 4
#define MY92XX_DCKI_PIN 5
#define MY92XX_COMMAND MY92XX_COMMAND_DEFAULT
// RGB on channels 0/1/2, either cool or warm white on channel 3
// The bulb *should* have cool leds, but could also have warm leds as a common defect
#define MY92XX_MAPPING 0, 1, 2, 3
// -----------------------------------------------------------------------------
// Bestek Smart Plug with 2 USB ports
// https://www.bestekcorp.com/bestek-smart-plug-works-with-amazon-alexa-google-assistant-and-ifttt-with-2-usb
@ -3024,10 +3096,9 @@
#define SHT3X_I2C_SUPPORT 1
#define SI7021_SUPPORT 1
#define PMSX003_SUPPORT 1
#define SENSEAIR_SUPPORT1
#define SENSEAIR_SUPPORT 1
#define VL53L1X_SUPPORT 1
// A bit of lights - pin 5
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER


+ 46
- 5
code/espurna/config/sensors.h View File

@ -99,6 +99,25 @@
#define ANALOG_DELAY 0 // Delay between samples in micros
#endif
//Use the following to perform scaling of raw analog values
// scaledRead = ( factor * rawRead ) + offset
//
//Please take note that the offset is not affected by the scaling factor
#ifndef ANALOG_FACTOR
#define ANALOG_FACTOR 1.0 // Multiply raw reading by this factor
#endif
#ifndef ANALOG_OFFSET
#define ANALOG_OFFSET 0.0 // Add this offset to *scaled* value
#endif
// Round to this number of decimals
#ifndef ANALOG_DECIMALS
#define ANALOG_DECIMALS 2
#endif
//------------------------------------------------------------------------------
// BH1750
// Enable support by passing BH1750_SUPPORT=1 build flag
@ -276,12 +295,28 @@
#define EMON_MAX_SAMPLES 1000 // Max number of samples to get
#define EMON_MAX_TIME 250 // Max time in ms to sample
#define EMON_FILTER_SPEED 512 // Mobile average filter speed
#define EMON_MAINS_VOLTAGE 230 // Mains voltage
#define EMON_REFERENCE_VOLTAGE 3.3 // Reference voltage of the ADC
#ifndef EMON_MAINS_VOLTAGE
#define EMON_MAINS_VOLTAGE 230 // Mains voltage
#endif
#ifndef EMON_CURRENT_RATIO
#define EMON_CURRENT_RATIO 30 // Current ratio in the clamp (30A/1V)
#endif
#ifndef EMON_REPORT_CURRENT
#define EMON_REPORT_CURRENT 0 // Report current
#endif
#ifndef EMON_REPORT_POWER
#define EMON_REPORT_POWER 1 // Report power
#endif
#ifndef EMON_REPORT_ENERGY
#define EMON_REPORT_ENERGY 1 // Report energy
#endif
//------------------------------------------------------------------------------
// Energy Monitor based on ADC121
@ -601,6 +636,8 @@
#define PULSEMETER_INTERRUPT_ON FALLING
#endif
#define PULSEMETER_DEBOUNCE 50 // Do not register pulses within less than 50 millis
//------------------------------------------------------------------------------
// PZEM004T based power monitor
// Enable support by passing PZEM004T_SUPPORT=1 build flag
@ -932,6 +969,10 @@
#include "../sensors/EventSensor.h"
#endif
#if EZOPH_SUPPORT
#include "../sensors/EZOPHSensor.h"
#endif
#if GEIGER_SUPPORT
#include "../sensors/GeigerSensor.h"
#endif
@ -944,6 +985,10 @@
#include "../sensors/HLW8012Sensor.h"
#endif
#if MAX6675_SUPPORT
#include "../sensors/MAX6675.h"
#endif
#if MHZ19_SUPPORT
#include "../sensors/MHZ19Sensor.h"
#endif
@ -1008,8 +1053,4 @@
#include "../sensors/VL53L1XSensor.h"
#endif
#if EZOPH_SUPPORT
#include "../sensors/EZOPHSensor.h"
#endif
#endif // SENSOR_SUPPORT

+ 1
- 1
code/espurna/config/version.h View File

@ -1,5 +1,5 @@
#define APP_NAME "ESPURNA"
#define APP_VERSION "1.13.3"
#define APP_VERSION "1.13.4-DEV"
#define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat"
#define CFG_VERSION 3

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


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


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


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


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


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


+ 5
- 1
code/espurna/nofuss.ino View File

@ -120,6 +120,9 @@ void nofussSetup() {
#if WEB_SUPPORT
wsSend_P(PSTR("{\"message\": 1}"));
#endif
// Disabling EEPROM rotation to prevent writing to EEPROM after the upgrade
eepromRotate(false);
}
if (code == NOFUSS_FILESYSTEM_UPDATE_ERROR) {
@ -147,7 +150,8 @@ void nofussSetup() {
}
if (code == NOFUSS_END) {
DEBUG_MSG_P(PSTR("[NoFUSS] End\n"));
DEBUG_MSG_P(PSTR("[NoFUSS] End\n"));
eepromRotate(true);
}
});


+ 3
- 1
code/espurna/relay.ino View File

@ -557,6 +557,8 @@ void _relayBoot() {
void _relayConfigure() {
for (unsigned int i=0; i<_relays.size(); i++) {
if (GPIO_NONE == _relays[i].pin) continue;
pinMode(_relays[i].pin, OUTPUT);
if (GPIO_NONE != _relays[i].reset_pin) {
pinMode(_relays[i].reset_pin, OUTPUT);
@ -1006,7 +1008,7 @@ void relaySetup() {
// No delay_on or off for these devices to easily allow having more than
// 8 channels. This behaviour will be recovered with v2.
for (unsigned char i=0; i < DUMMY_RELAY_COUNT; i++) {
_relays.push_back((relay_t) {0, RELAY_TYPE_NORMAL, 0, 0, 0});
_relays.push_back((relay_t) {GPIO_NONE, RELAY_TYPE_NORMAL, 0, 0, 0});
}
#else


+ 18
- 0
code/espurna/sensor.ino View File

@ -56,6 +56,7 @@ unsigned char _magnitudeDecimals(unsigned char type) {
// Hardcoded decimals (these should be linked to the unit, instead of the magnitude)
if (type == MAGNITUDE_ANALOG) return ANALOG_DECIMALS;
if (type == MAGNITUDE_ENERGY ||
type == MAGNITUDE_ENERGY_DELTA) {
if (_sensor_energy_units == ENERGY_KWH) return 3;
@ -203,6 +204,7 @@ void _sensorWebSocketStart(JsonObject& root) {
#if PULSEMETER_SUPPORT
if (sensor->getID() == SENSOR_PULSEMETER_ID) {
root["pmVisible"] = 1;
root["pwrRatioE"] = ((PulseMeterSensor *) sensor)->getEnergyRatio();
}
#endif
@ -414,6 +416,9 @@ void _sensorLoad() {
AnalogSensor * sensor = new AnalogSensor();
sensor->setSamples(ANALOG_SAMPLES);
sensor->setDelay(ANALOG_DELAY);
//CICM For analog scaling
sensor->setFactor(ANALOG_FACTOR);
sensor->setOffset(ANALOG_OFFSET);
_sensors.push_back(sensor);
}
#endif
@ -645,6 +650,7 @@ void _sensorLoad() {
PulseMeterSensor * sensor = new PulseMeterSensor();
sensor->setGPIO(PULSEMETER_PIN);
sensor->setEnergyRatio(PULSEMETER_ENERGY_RATIO);
sensor->setDebounceTime(PULSEMETER_DEBOUNCE);
_sensors.push_back(sensor);
}
#endif
@ -720,6 +726,16 @@ void _sensorLoad() {
}
#endif
#if MAX6675_SUPPORT
{
MAX6675Sensor * sensor = new MAX6675Sensor();
sensor->setCS(MAX6675_CS_PIN);
sensor->setSO(MAX6675_SO_PIN);
sensor->setSCK(MAX6675_SCK_PIN);
_sensors.push_back(sensor);
}
#endif
#if VEML6075_SUPPORT
{
VEML6075Sensor * sensor = new VEML6075Sensor();
@ -1095,6 +1111,8 @@ void _sensorConfigure() {
delSetting("eneTotal");
_sensorResetTS();
}
sensor->setEnergyRatio(getSetting("pwrRatioE", PULSEMETER_ENERGY_RATIO).toInt());
}
#endif // PULSEMETER_SUPPORT


+ 42
- 1
code/espurna/sensors/AnalogSensor.h View File

@ -35,6 +35,16 @@ class AnalogSensor : public BaseSensor {
_micros = micros;
}
void setFactor(double factor) {
//DEBUG_MSG(("[ANALOG_SENSOR] Factor set to: %s \n"), String(factor,6).c_str());
_factor = factor;
}
void setOffset(double offset) {
//DEBUG_MSG(("[ANALOG_SENSOR] Factor set to: %s \n"), String(offset,6).c_str());
_offset = offset;
}
// ---------------------------------------------------------------------
unsigned int getSamples() {
@ -45,6 +55,14 @@ class AnalogSensor : public BaseSensor {
return _micros;
}
double getFactor() {
return _factor;
}
double getOffset() {
return _offset;
}
// ---------------------------------------------------------------------
// Sensor API
// ---------------------------------------------------------------------
@ -77,6 +95,7 @@ class AnalogSensor : public BaseSensor {
}
// Current value for slot # index
// Changed return type as moving to scaled value
double value(unsigned char index) {
if (index == 0) return _read();
return 0;
@ -84,7 +103,9 @@ class AnalogSensor : public BaseSensor {
protected:
unsigned int _read() {
//CICM: this should be for raw values
// renaming protected function "_read" to "_rawRead"
unsigned int _rawRead() {
if (1 == _samples) return analogRead(0);
unsigned long sum = 0;
for (unsigned int i=0; i<_samples; i++) {
@ -94,8 +115,28 @@ class AnalogSensor : public BaseSensor {
return sum / _samples;
}
//CICM: and proper read should be scalable and thus needs sign
//and decimal part
double _read() {
//Raw measure could also be a class variable with getter so that can
//be reported through MQTT, ...
unsigned int rawValue;
double scaledValue;
// Debugging doubles to string
//DEBUG_MSG(("[ANALOG_SENSOR] Started standard read, factor: %s , offset: %s, decimals: %d \n"), String(_factor).c_str(), String(_offset).c_str(), ANALOG_DECIMALS);
rawValue = _rawRead();
//DEBUG_MSG(("[ANALOG_SENSOR] Raw read received: %d \n"), rawValue);
scaledValue = _factor*rawValue + _offset;
//DEBUG_MSG(("[ANALOG_SENSOR] Scaled value result: %s \n"), String(scaledValue).c_str());
return scaledValue;
}
unsigned int _samples = 1;
unsigned long _micros = 0;
//CICM: for scaling and offset, also with getters and setters
double _factor = 1.0;
double _offset = 0.0;
};


+ 150
- 0
code/espurna/sensors/MAX6675.h View File

@ -0,0 +1,150 @@
// -----------------------------------------------------------------------------
// MAX6675 Sensor
// Uses MAX6675_Thermocouple library
// Copyright (C) 2017-2018 by Xose Pérez <andrade dot luciano at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && MAX6675_SUPPORT
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
#include <vector>
#include <MAX6675.h>
#define MAX6675_READ_INTERVAL 3000
class MAX6675Sensor : public BaseSensor {
public:
// ---------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------
MAX6675Sensor(): BaseSensor() {
_sensor_id = SENSOR_MAX6675_ID;
}
~MAX6675Sensor() {
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
void setCS(unsigned char pin_cs) {
if (_pin_cs == pin_cs) return;
_pin_cs = pin_cs;
_dirty = true;
}
void setSO(unsigned char pin_so) {
if (_pin_so == pin_so) return;
_pin_so = pin_so;
_dirty = true;
}
void setSCK(unsigned char pin_sck) {
if (_pin_sck == pin_sck) return;
_pin_sck = pin_sck;
_dirty = true;
}
// ---------------------------------------------------------------------
// Sensor API
// ---------------------------------------------------------------------
// Initialization method, must be idempotent
void begin() {
if (!_dirty) return;
//// MAX6675
int units = 1; // Units to readout temp (0 = raw, 1 = ˚C, 2 = ˚F)
if (_max) delete _max;
_max = new MAX6675(_pin_cs,_pin_so,_pin_sck,units);
_count = 1;
_ready = true;
_dirty = false;
}
// Loop-like method, call it in your main loop
void tick() {
static unsigned long last = 0;
if (millis() - last < MAX6675_READ_INTERVAL) return;
last = millis();
last_read = _max->read_temp();
}
// Descriptive name of the sensor
String description() {
char buffer[20];
//snprintf(buffer, sizeof(buffer), "MAX6675 @ CS %d", _gpio);
snprintf(buffer, sizeof(buffer), "MAX6675 ");
return String(buffer);
}
String address(unsigned char index){
return String("@ address");
}
// Address of the device
// Descriptive name of the slot # index
String slot(unsigned char index) {
if (index < _count) {
// char buffer[40];
// uint8_t * address = _devices[index].address;
// snprintf(buffer, sizeof(buffer), "%s (%02X%02X%02X%02X%02X%02X%02X%02X) @ GPIO%d",
// chipAsString(index).c_str(),
// address[0], address[1], address[2], address[3],
// address[4], address[5], address[6], address[7],
// _gpio
// );
return description();
}
return String();
}
// Type for slot # index
unsigned char type(unsigned char index) {
if (index < _count) return MAGNITUDE_TEMPERATURE;
return MAGNITUDE_NONE;
}
// Pre-read hook (usually to populate registers with up-to-date data)
void pre() {
_error = SENSOR_ERROR_OK;
}
// Current value for slot # index
double value(unsigned char index) {
return last_read;
}
protected:
// ---------------------------------------------------------------------
// Protected
// ---------------------------------------------------------------------
unsigned int _pin_cs = MAX6675_CS_PIN;
unsigned int _pin_so = MAX6675_SO_PIN;
unsigned int _pin_sck = MAX6675_SCK_PIN;
bool _busy = false;
double last_read = 0;
MAX6675 * _max = NULL;
};
#endif // SENSOR_SUPPORT && MAX6675_SUPPORT

+ 14
- 2
code/espurna/sensors/PulseMeterSensor.h View File

@ -43,16 +43,24 @@ class PulseMeterSensor : public BaseSensor {
if (ratio > 0) _ratio = ratio;
}
void setDebounceTime(unsigned long debounce) {
_debounce = debounce;
}
// ---------------------------------------------------------------------
unsigned char getGPIO() {
return _gpio;
}
unsigned char getEnergyRatio() {
unsigned long getEnergyRatio() {
return _ratio;
}
unsigned long getDebounceTime() {
return _debounce;
}
// ---------------------------------------------------------------------
// Sensors API
// ---------------------------------------------------------------------
@ -113,7 +121,10 @@ class PulseMeterSensor : public BaseSensor {
// Handle interrupt calls
void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) {
if (gpio == _gpio) {
static unsigned long last = 0;
if (millis() - last > _debounce) {
last = millis();
_pulses++;
}
}
@ -151,6 +162,7 @@ class PulseMeterSensor : public BaseSensor {
unsigned char _previous = GPIO_NONE;
unsigned char _gpio = GPIO_NONE;
unsigned long _ratio = PULSEMETER_ENERGY_RATIO;
unsigned long _debounce = PULSEMETER_DEBOUNCE;
double _active = 0;
double _energy = 0;


+ 4
- 6
code/espurna/settings.ino View File

@ -274,12 +274,10 @@ void _settingsInitCommands() {
DEBUG_MSG_P(PSTR("+OK\n"));
});
#if WEB_SUPPORT
settingsRegisterCommand(F("RELOAD"), [](Embedis* e) {
espurnaReload();
DEBUG_MSG_P(PSTR("+OK\n"));
});
#endif
settingsRegisterCommand(F("RELOAD"), [](Embedis* e) {
espurnaReload();
DEBUG_MSG_P(PSTR("+OK\n"));
});
settingsRegisterCommand(F("RESET"), [](Embedis* e) {
DEBUG_MSG_P(PSTR("+OK\n"));


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


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


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


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


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


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


+ 38
- 28
code/espurna/telnet.ino View File

@ -15,9 +15,9 @@ Parts of the code have been borrowed from Thomas Sarlandie's NetServer
AsyncServer * _telnetServer;
AsyncClient * _telnetClients[TELNET_MAX_CLIENTS];
bool _telnetFirst = true;
#if TELNET_PASSWORD
bool _authenticated[TELNET_MAX_CLIENTS];
#endif
bool _telnetAuth = TELNET_AUTHENTICATION;
bool _telnetClientsAuth[TELNET_MAX_CLIENTS];
// -----------------------------------------------------------------------------
// Private methods
@ -32,6 +32,7 @@ bool _telnetWebSocketOnReceive(const char * key, JsonVariant& value) {
void _telnetWebSocketOnSend(JsonObject& root) {
root["telnetVisible"] = 1;
root["telnetSTA"] = getSetting("telnetSTA", TELNET_STA).toInt() == 1;
root["telnetAuth"] = getSetting("telnetAuth", TELNET_AUTHENTICATION).toInt() == 1;
}
#endif
@ -54,16 +55,12 @@ bool _telnetWrite(unsigned char clientId, void *data, size_t len) {
unsigned char _telnetWrite(void *data, size_t len) {
unsigned char count = 0;
for (unsigned char i = 0; i < TELNET_MAX_CLIENTS; i++) {
// Do not send broadcast messages to unauthenticated clients
if (_telnetAuth && !_telnetClientsAuth[i]) {
continue;
}
#if TELNET_PASSWORD
// Do not send broadcast messages to unauthenticated clients
if (_authenticated[i]) {
if (_telnetWrite(i, data, len)) ++count;
}
#else
if (_telnetWrite(i, data, len)) ++count;
#endif
if (_telnetWrite(i, data, len)) ++count;
}
return count;
}
@ -96,20 +93,24 @@ void _telnetData(unsigned char clientId, void *data, size_t len) {
return;
}
// Password
#if TELNET_PASSWORD
if (!_authenticated[clientId]) {
String password = getAdminPass();
if (strncmp(p, password.c_str(), password.length()) == 0) {
DEBUG_MSG_P(PSTR("[TELNET] Client #%d authenticated\n"), clientId);
_telnetWrite(clientId, "Welcome!\n");
_authenticated[clientId] = true;
} else {
_telnetWrite(clientId, "Password: ");
}
return;
// Password prompt (disable on CORE variant)
#ifdef ESPURNA_CORE
const bool authenticated = true;
#else
const bool authenticated = _telnetClientsAuth[clientId];
#endif
if (_telnetAuth && !authenticated) {
String password = getAdminPass();
if (strncmp(p, password.c_str(), password.length()) == 0) {
DEBUG_MSG_P(PSTR("[TELNET] Client #%d authenticated\n"), clientId);
_telnetWrite(clientId, "Welcome!\n");
_telnetClientsAuth[clientId] = true;
} else {
_telnetWrite(clientId, "Password: ");
}
#endif // TELNET_PASSWORD
return;
}
// Inject command
settingsInject(data, len);
@ -175,9 +176,11 @@ void _telnetNewClient(AsyncClient *client) {
debugClearCrashInfo();
#endif
#if TELNET_PASSWORD
_authenticated[i] = false;
_telnetWrite(i, "Password: ");
#ifdef ESPURNA_CORE
_telnetClientsAuth[i] = true;
#else
_telnetClientsAuth[i] = !_telnetAuth;
if (_telnetAuth) _telnetWrite(i, "Password: ");
#endif
_telnetFirst = true;
@ -214,6 +217,10 @@ unsigned char telnetWrite(unsigned char ch) {
return _telnetWrite(data, 1);
}
void _telnetConfigure() {
_telnetAuth = getSetting("telnetAuth", TELNET_AUTHENTICATION).toInt() == 1;
}
void telnetSetup() {
_telnetServer = new AsyncServer(TELNET_PORT);
@ -227,6 +234,9 @@ void telnetSetup() {
wsOnReceiveRegister(_telnetWebSocketOnReceive);
#endif
espurnaRegisterReload(_telnetConfigure);
_telnetConfigure();
DEBUG_MSG_P(PSTR("[TELNET] Listening on port %d\n"), TELNET_PORT);
}


+ 11
- 4
code/espurna/thinkspeak.ino View File

@ -25,6 +25,8 @@ const char THINGSPEAK_REQUEST_TEMPLATE[] PROGMEM =
"%s\r\n";
bool _tspk_enabled = false;
bool _tspk_clear = false;
char * _tspk_queue[THINGSPEAK_FIELDS] = {NULL};
bool _tspk_flush = false;
@ -45,6 +47,7 @@ void _tspkWebSocketOnSend(JsonObject& root) {
root["tspkEnabled"] = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
root["tspkKey"] = getSetting("tspkKey");
root["tspkClear"] = getSetting("tspkClear", THINGSPEAK_CLEAR_CACHE).toInt() == 1;
JsonArray& relays = root.createNestedArray("tspkRelays");
for (byte i=0; i<relayCount(); i++) {
@ -71,6 +74,7 @@ void _tspkWebSocketOnSend(JsonObject& root) {
#endif
void _tspkConfigure() {
_tspk_clear = getSetting("tspkClear", THINGSPEAK_CLEAR_CACHE).toInt() == 1;
_tspk_enabled = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
if (_tspk_enabled && (getSetting("tspkKey").length() == 0)) {
_tspk_enabled = false;
@ -221,10 +225,12 @@ void _tspkEnqueue(unsigned char index, char * payload) {
}
void _tspkClearQueue() {
for (unsigned char id=0; id<THINGSPEAK_FIELDS; id++) {
if (_tspk_queue[id] != NULL) {
free(_tspk_queue[id]);
_tspk_queue[id] = NULL;
if (_tspk_clear) {
for (unsigned char id=0; id<THINGSPEAK_FIELDS; id++) {
if (_tspk_queue[id] != NULL) {
free(_tspk_queue[id]);
_tspk_queue[id] = NULL;
}
}
}
}
@ -250,6 +256,7 @@ void _tspkFlush() {
}
}
// -----------------------------------------------------------------------------
bool tspkEnqueueRelay(unsigned char index, unsigned char status) {


+ 3
- 0
code/espurna/utils.ino View File

@ -236,6 +236,9 @@ void heartbeat() {
#if (HEARTBEAT_REPORT_FREEHEAP)
idbSend(MQTT_TOPIC_FREEHEAP, String(free_heap).c_str());
#endif
#if (HEARTBEAT_REPORT_RSSI)
idbSend(MQTT_TOPIC_RSSI, String(WiFi.RSSI()).c_str());
#endif
#endif
}


+ 5
- 6
code/gulpfile.js View File

@ -27,7 +27,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
const gulp = require('gulp');
const runSequence = require('run-sequence');
const through = require('through2');
const htmlmin = require('gulp-htmlmin');
@ -191,15 +190,15 @@ gulp.task('webui_all', function() {
return buildWebUI('all');
});
gulp.task('webui', function(cb) {
runSequence([
gulp.task('webui',
gulp.parallel(
'webui_small',
'webui_sensor',
'webui_light',
'webui_rfbridge',
'webui_rfm69',
'webui_all'
], cb);
});
)
);
gulp.task('default', ['webui']);
gulp.task('default', gulp.series('webui'));

+ 50
- 13
code/html/index.html View File

@ -127,6 +127,10 @@
<a href="#" class="pure-menu-link" data="panel-mqtt">MQTT</a>
</li>
<li class="pure-menu-item module module-nofuss">
<a href="#" class="pure-menu-link" data="panel-nofuss">NOFUSS</a>
</li>
<li class="pure-menu-item module module-ntp">
<a href="#" class="pure-menu-link" data="panel-ntp">NTP</a>
</li>
@ -608,17 +612,12 @@
<div class="pure-u-1 pure-u-lg-3-4 hint">Turn ON to be able to telnet to your device while connected to your home router.<br />TELNET is always enabled in AP mode.</div>
</div>
<div class="pure-g module module-nofuss">
<label class="pure-u-1 pure-u-lg-1-4">Automatic remote updates (NoFUSS)</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="nofussEnabled" /></div>
</div>
<div class="pure-g module module-nofuss">
<label class="pure-u-1 pure-u-lg-1-4">NoFUSS server</label>
<input name="nofussServer" class="pure-u-1 pure-u-lg-3-4" type="text" tabindex="15" />
<div class="pure-g module module-telnet">
<label class="pure-u-1 pure-u-lg-1-4">TELNET Password</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="telnetAuth" /></div>
<div class="pure-u-0 pure-u-lg-1-2"></div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">This name address of the NoFUSS server for automatic remote updates (see https://bitbucket.org/xoseperez/nofuss).</div>
<div class="pure-u-1 pure-u-lg-3-4 hint">Request password when starting telnet session</div>
</div>
<div class="pure-g">
@ -907,6 +906,33 @@
</div>
</form>
<form id="form-nofuss" class="pure-form form-settings">
<div class="panel" id="panel-nofuss">
<div class="header">
<h1>NoFUSS</h1>
<h2>Automatically upgrade the firmware (see <a href="https://bitbucket.org/xoseperez/nofuss">xoseperez/nofuss</a> for details)</h2>
</div>
<div class="page">
<fieldset>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Enable</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="nofussEnabled" /></div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Server</label>
<input name="nofussServer" class="pure-u-1 pure-u-lg-3-4" type="text" tabindex="15" />
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">Address of the NoFUSS server</div>
</div>
</fieldset>
</div>
</div>
</form>
<form id="form-ntp" class="pure-form form-settings">
<div class="panel" id="panel-ntp">
@ -1079,9 +1105,21 @@
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="tspkEnabled" tabindex="30" /></div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Clear cache</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="tspkClear" tabindex="31" /></div>
<div class="pure-u-0 pure-u-lg-1-2"></div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
With every POST to thinkspeak.com only enqueued fields are sent.
If you select to clear the cache after every sending this will result in only those fields that have changed will be posted.
If you want all fields to be sent with every POST do not clear the cache.
</div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Thingspeak API Key</label>
<input class="pure-u-1 pure-u-lg-3-4" name="tspkKey" type="text" tabindex="31" />
<input class="pure-u-1 pure-u-lg-3-4" name="tspkKey" type="text" tabindex="32" />
</div>
<legend>Sensors &amp; actuators</legend>
@ -1334,8 +1372,7 @@
<div class="pure-g module module-pm">
<label class="pure-u-1 pure-u-lg-1-4">Energy Ratio</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="pwrRatioE" tabindex="55" /></div>
<div class="pure-u-0 pure-u-lg-1-2"></div>
<input class="pure-u-1 pure-u-lg-3-4" name="pwrRatioE" type="text" tabindex="55" placeholder="0" />
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">Energy ratio in pulses/kWh.</div>
</div>


+ 2292
- 931
code/package-lock.json
File diff suppressed because it is too large
View File


+ 2
- 5
code/package.json View File

@ -1,12 +1,11 @@
{
"name": "esp8266-filesystem-builder",
"version": "0.2.2",
"description": "Gulp based build system for ESP8266 file system files",
"main": "gulpfile.js",
"author": "Xose Pérez <xose.perez@gmail.com>",
"license": "GPL-3.0",
"devDependencies": {
"gulp": "^3.9.1",
"gulp": "^4.0.0",
"gulp-base64-favicon": "^1.0.2",
"gulp-crass": "^0.2.2",
"gulp-css-base64": "^1.3.4",
@ -17,8 +16,6 @@
"gulp-inline": "^0.1.1",
"gulp-remove-code": "^3.0.4",
"gulp-rename": "^1.4.0",
"gulp-replace": "^1.0.0",
"map-stream": "0.0.7",
"run-sequence": "^2.2.1"
"gulp-replace": "^1.0.0"
}
}

+ 51
- 1
code/platformio.ini View File

@ -41,7 +41,7 @@ debug_flags = -DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY = v2 Lower Memory
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH = v2 Higher Bandwidth
# ------------------------------------------------------------------------------
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=400 -DNO_GLOBAL_EEPROM ${sysenv.ESPURNA_FLAGS} -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=400 -DNO_GLOBAL_EEPROM ${sysenv.ESPURNA_FLAGS} -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
build_flags_512k = ${common.build_flags} -Wl,-Teagle.flash.512k0m1s.ld
build_flags_1m0m = ${common.build_flags} -Wl,-Teagle.flash.1m0m1s.ld
build_flags_2m1m = ${common.build_flags} -Wl,-Teagle.flash.2m1m4s.ld
@ -99,6 +99,7 @@ lib_deps =
NewPing
https://github.com/sparkfun/SparkFun_VEML6075_Arduino_Library#V_1.0.3
https://github.com/pololu/vl53l1x-arduino#1.0.1
https://github.com/mcleng/MAX6675-Library#2.0.1
lib_ignore =
# ------------------------------------------------------------------------------
@ -2304,6 +2305,55 @@ upload_flags = ${common.upload_flags}
monitor_speed = ${common.monitor_speed}
extra_scripts = ${common.extra_scripts}
[env:lombex-lux-nova2-tunable-white]
platform = ${common.platform}
framework = ${common.framework}
board = ${common.board_1m}
board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -DLOMBEX_LUX_NOVA2_TUNABLE_WHITE
monitor_speed = ${common.monitor_speed}
extra_scripts = ${common.extra_scripts}
[env:lombex-lux-nova2-tunable-white-ota]
platform = ${common.platform}
framework = ${common.framework}
board = ${common.board_1m}
board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -DLOMBEX_LUX_NOVA2_TUNABLE_WHITE
upload_speed = ${common.upload_speed}
upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags}
monitor_speed = ${common.monitor_speed}
extra_scripts = ${common.extra_scripts}
[env:lombex-lux-nova2-white-color]
platform = ${common.platform}
framework = ${common.framework}
board = ${common.board_1m}
board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -DLOMBEX_LUX_NOVA2_WHITE_COLOR
monitor_speed = ${common.monitor_speed}
extra_scripts = ${common.extra_scripts}
[env:lombex-lux-nova2-white-color-ota]
platform = ${common.platform}
framework = ${common.framework}
board = ${common.board_1m}
board_build.flash_mode = ${common.flash_mode}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m0m} -DLOMBEX_LUX_NOVA2_WHITE_COLOR
upload_speed = ${common.upload_speed}
upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags}
monitor_speed = ${common.monitor_speed}
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------
# GENERIC OTA ENVIRONMENTS


BIN
images/devices/lombex-lux-nova-flash-2.jpg View File

Before After
Width: 2940  |  Height: 1724  |  Size: 1022 KiB

BIN
images/devices/lombex-lux-nova-flash.jpg View File

Before After
Width: 2718  |  Height: 2751  |  Size: 1.5 MiB

BIN
images/devices/lombex-lux-nova.jpg View File

Before After
Width: 300  |  Height: 400  |  Size: 5.6 KiB

Loading…
Cancel
Save