From 68e7e5a51ca9e6d3b181488c533ebce7714b1c42 Mon Sep 17 00:00:00 2001 From: Thomas Eckerstorfer Date: Sat, 12 Oct 2019 15:03:35 +0200 Subject: [PATCH] AS3935 Lightning sensor (#666) * added tx20 wind speed sensor * added test * fixed lint errors * fixed more lint errors * updated tx20 * updated tx20 sensor * updated to new structure and removed static variables * removed content from __init__.py * fixing lint errors * resolved issues from review * added as3935 sensor * updated as3935 with more settings * update * support for i2c + spi updated * added tests and various fixes * added tx20 wind speed sensor * fixed lint errors * fixed more lint errors * updated tx20 * updated tx20 sensor * updated to new structure and removed static variables * removed content from __init__.py * fixing lint errors * resolved issues from review * added as3935 sensor * updated as3935 with more settings * update * support for i2c + spi updated * added tests and various fixes * updated tests * fixed style issues * Remove debug line * Update log levels * Reformat * Auto-convert to int Co-authored-by: Thomas Co-authored-by: Otto Winter --- esphome/components/as3935_base/__init__.py | 54 +++++ .../components/as3935_base/as3935_base.cpp | 206 ++++++++++++++++++ esphome/components/as3935_base/as3935_base.h | 102 +++++++++ .../components/as3935_base/binary_sensor.py | 16 ++ esphome/components/as3935_base/sensor.py | 30 +++ esphome/components/as3935_i2c/__init__.py | 20 ++ esphome/components/as3935_i2c/as3935_i2c.cpp | 36 +++ esphome/components/as3935_i2c/as3935_i2c.h | 21 ++ esphome/components/as3935_spi/__init__.py | 20 ++ esphome/components/as3935_spi/as3935_spi.cpp | 49 +++++ esphome/components/as3935_spi/as3935_spi.h | 27 +++ esphome/components/i2c/i2c.cpp | 2 +- esphome/const.py | 14 +- script/quicklint | 2 +- script/setup | 2 +- tests/test1.yaml | 12 +- tests/test2.yaml | 11 + 17 files changed, 619 insertions(+), 5 deletions(-) create mode 100644 esphome/components/as3935_base/__init__.py create mode 100644 esphome/components/as3935_base/as3935_base.cpp create mode 100644 esphome/components/as3935_base/as3935_base.h create mode 100644 esphome/components/as3935_base/binary_sensor.py create mode 100644 esphome/components/as3935_base/sensor.py create mode 100644 esphome/components/as3935_i2c/__init__.py create mode 100644 esphome/components/as3935_i2c/as3935_i2c.cpp create mode 100644 esphome/components/as3935_i2c/as3935_i2c.h create mode 100644 esphome/components/as3935_spi/__init__.py create mode 100644 esphome/components/as3935_spi/as3935_spi.cpp create mode 100644 esphome/components/as3935_spi/as3935_spi.h diff --git a/esphome/components/as3935_base/__init__.py b/esphome/components/as3935_base/__init__.py new file mode 100644 index 0000000000..86b7128bb2 --- /dev/null +++ b/esphome/components/as3935_base/__init__.py @@ -0,0 +1,54 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.const import CONF_PIN, CONF_INDOOR, CONF_WATCHDOG_THRESHOLD, \ + CONF_NOISE_LEVEL, CONF_SPIKE_REJECTION, CONF_LIGHTNING_THRESHOLD, \ + CONF_MASK_DISTURBER, CONF_DIV_RATIO, CONF_CAP +from esphome.core import coroutine + + +AUTO_LOAD = ['sensor', 'binary_sensor'] +MULTI_CONF = True + +CONF_AS3935_ID = 'as3935_id' + +as3935_base_ns = cg.esphome_ns.namespace('as3935_base') +AS3935 = as3935_base_ns.class_('AS3935Component', cg.Component) + +AS3935_SCHEMA = cv.Schema({ + cv.GenerateID(): cv.declare_id(AS3935), + cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema, + pins.validate_has_interrupt), + cv.Optional(CONF_INDOOR): cv.boolean, + cv.Optional(CONF_WATCHDOG_THRESHOLD): cv.int_range(min=1, max=10), + cv.Optional(CONF_NOISE_LEVEL): cv.int_range(min=1, max=7), + cv.Optional(CONF_SPIKE_REJECTION): cv.int_range(min=1, max=11), + cv.Optional(CONF_LIGHTNING_THRESHOLD): cv.one_of(0, 1, 5, 9, 16, int=True), + cv.Optional(CONF_MASK_DISTURBER): cv.boolean, + cv.Optional(CONF_DIV_RATIO): cv.one_of(0, 16, 22, 64, 128, int=True), + cv.Optional(CONF_CAP): cv.int_range(min=0, max=15), +}) + + +@coroutine +def setup_as3935(var, config): + yield cg.register_component(var, config) + + pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + cg.add(var.set_pin(pin)) + if CONF_INDOOR in config: + cg.add(var.set_indoor(config[CONF_INDOOR])) + if CONF_WATCHDOG_THRESHOLD in config: + cg.add(var.set_watchdog_threshold(config[CONF_WATCHDOG_THRESHOLD])) + if CONF_NOISE_LEVEL in config: + cg.add(var.set_noise_level(config[CONF_NOISE_LEVEL])) + if CONF_SPIKE_REJECTION in config: + cg.add(var.set_spike_rejection(config[CONF_SPIKE_REJECTION])) + if CONF_LIGHTNING_THRESHOLD in config: + cg.add(var.set_lightning_threshold(config[CONF_LIGHTNING_THRESHOLD])) + if CONF_MASK_DISTURBER in config: + cg.add(var.set_mask_disturber(config[CONF_MASK_DISTURBER])) + if CONF_DIV_RATIO in config: + cg.add(var.set_div_ratio(config[CONF_DIV_RATIO])) + if CONF_CAP in config: + cg.add(var.set_cap(config[CONF_CAP])) diff --git a/esphome/components/as3935_base/as3935_base.cpp b/esphome/components/as3935_base/as3935_base.cpp new file mode 100644 index 0000000000..a0aedb4a16 --- /dev/null +++ b/esphome/components/as3935_base/as3935_base.cpp @@ -0,0 +1,206 @@ +#include "as3935_base.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace as3935_base { + +static const char *TAG = "as3935_base"; + +void AS3935Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up AS3935..."); + + this->pin_->setup(); + this->store_.pin = this->pin_->to_isr(); + LOG_PIN(" Interrupt Pin: ", this->pin_); + this->pin_->attach_interrupt(AS3935ComponentStore::gpio_intr, &this->store_, RISING); +} + +void AS3935Component::dump_config() { + ESP_LOGCONFIG(TAG, "AS3935:"); + LOG_PIN(" Interrupt Pin: ", this->pin_); +} + +float AS3935Component::get_setup_priority() const { return setup_priority::DATA; } + +void AS3935Component::loop() { + if (!this->store_.interrupt) + return; + + uint8_t int_value = this->read_interrupt_register_(); + if (int_value == NOISE_INT) { + ESP_LOGI(TAG, "Noise was detected - try increasing the noise level value!"); + } else if (int_value == DISTURBER_INT) { + ESP_LOGI(TAG, "Disturber was detected - try increasing the spike rejection value!"); + } else if (int_value == LIGHTNING_INT) { + ESP_LOGI(TAG, "Lightning has been detected!"); + if (this->thunder_alert_binary_sensor_ != nullptr) + this->thunder_alert_binary_sensor_->publish_state(true); + uint8_t distance = this->get_distance_to_storm_(); + if (this->distance_sensor_ != nullptr) + this->distance_sensor_->publish_state(distance); + uint32_t energy = this->get_lightning_energy_(); + if (this->energy_sensor_ != nullptr) + this->energy_sensor_->publish_state(energy); + } + this->thunder_alert_binary_sensor_->publish_state(false); + this->store_.interrupt = false; +} + +void AS3935Component::set_indoor(bool indoor) { + ESP_LOGD(TAG, "Setting indoor to %d", indoor); + if (indoor) + this->write_register(AFE_GAIN, GAIN_MASK, INDOOR, 1); + else + this->write_register(AFE_GAIN, GAIN_MASK, OUTDOOR, 1); +} +// REG0x01, bits[3:0], manufacturer default: 0010 (2). +// This setting determines the threshold for events that trigger the +// IRQ Pin. +void AS3935Component::set_watchdog_threshold(uint8_t sensitivity) { + ESP_LOGD(TAG, "Setting watchdog sensitivity to %d", sensitivity); + if ((sensitivity < 1) || (sensitivity > 10)) // 10 is the max sensitivity setting + return; + this->write_register(THRESHOLD, THRESH_MASK, sensitivity, 0); +} + +// REG0x01, bits [6:4], manufacturer default: 010 (2). +// The noise floor level is compared to a known reference voltage. If this +// level is exceeded the chip will issue an interrupt to the IRQ pin, +// broadcasting that it can not operate properly due to noise (INT_NH). +// Check datasheet for specific noise level tolerances when setting this register. +void AS3935Component::set_noise_level(uint8_t floor) { + ESP_LOGD(TAG, "Setting noise level to %d", floor); + if ((floor < 1) || (floor > 7)) + return; + + this->write_register(THRESHOLD, NOISE_FLOOR_MASK, floor, 4); +} +// REG0x02, bits [3:0], manufacturer default: 0010 (2). +// This setting, like the watchdog threshold, can help determine between false +// events and actual lightning. The shape of the spike is analyzed during the +// chip's signal validation routine. Increasing this value increases robustness +// at the cost of sensitivity to distant events. +void AS3935Component::set_spike_rejection(uint8_t spike_sensitivity) { + ESP_LOGD(TAG, "Setting spike rejection to %d", spike_sensitivity); + if ((spike_sensitivity < 1) || (spike_sensitivity > 11)) + return; + + this->write_register(LIGHTNING_REG, SPIKE_MASK, spike_sensitivity, 0); +} +// REG0x02, bits [5:4], manufacturer default: 0 (single lightning strike). +// The number of lightning events before IRQ is set high. 15 minutes is The +// window of time before the number of detected lightning events is reset. +// The number of lightning strikes can be set to 1,5,9, or 16. +void AS3935Component::set_lightning_threshold(uint8_t strikes) { + ESP_LOGD(TAG, "Setting lightning threshold to %d", strikes); + if (strikes == 1) + this->write_register(LIGHTNING_REG, ((1 << 5) | (1 << 4)), 0, 4); // Demonstrative + if (strikes == 5) + this->write_register(LIGHTNING_REG, ((1 << 5) | (1 << 4)), 1, 4); + if (strikes == 9) + this->write_register(LIGHTNING_REG, ((1 << 5) | (1 << 4)), 1, 5); + if (strikes == 16) + this->write_register(LIGHTNING_REG, ((1 << 5) | (1 << 4)), 3, 4); +} +// REG0x03, bit [5], manufacturer default: 0. +// This setting will return whether or not disturbers trigger the IRQ Pin. +void AS3935Component::set_mask_disturber(bool enabled) { + ESP_LOGD(TAG, "Setting mask disturber to %d", enabled); + if (enabled) { + this->write_register(INT_MASK_ANT, (1 << 5), 1, 5); + } else { + this->write_register(INT_MASK_ANT, (1 << 5), 0, 5); + } +} +// REG0x03, bit [7:6], manufacturer default: 0 (16 division ratio). +// The antenna is designed to resonate at 500kHz and so can be tuned with the +// following setting. The accuracy of the antenna must be within 3.5 percent of +// that value for proper signal validation and distance estimation. +void AS3935Component::set_div_ratio(uint8_t div_ratio) { + ESP_LOGD(TAG, "Setting div ratio to %d", div_ratio); + if (div_ratio == 16) + this->write_register(INT_MASK_ANT, ((1 << 7) | (1 << 6)), 0, 6); + else if (div_ratio == 22) + this->write_register(INT_MASK_ANT, ((1 << 7) | (1 << 6)), 1, 6); + else if (div_ratio == 64) + this->write_register(INT_MASK_ANT, ((1 << 7) | (1 << 6)), 1, 7); + else if (div_ratio == 128) + this->write_register(INT_MASK_ANT, ((1 << 7) | (1 << 6)), 3, 6); +} +// REG0x08, bits [3:0], manufacturer default: 0. +// This setting will add capacitance to the series RLC antenna on the product +// to help tune its resonance. The datasheet specifies being within 3.5 percent +// of 500kHz to get optimal lightning detection and distance sensing. +// It's possible to add up to 120pF in steps of 8pF to the antenna. +void AS3935Component::set_cap(uint8_t eight_pico_farad) { + ESP_LOGD(TAG, "Setting tune cap to %d pF", eight_pico_farad * 8); + if (eight_pico_farad > 15) + return; + + this->write_register(FREQ_DISP_IRQ, CAP_MASK, eight_pico_farad, 0); +} + +// REG0x03, bits [3:0], manufacturer default: 0. +// When there is an event that exceeds the watchdog threshold, the register is written +// with the type of event. This consists of two messages: INT_D (disturber detected) and +// INT_L (Lightning detected). A third interrupt INT_NH (noise level too HIGH) +// indicates that the noise level has been exceeded and will persist until the +// noise has ended. Events are active HIGH. There is a one second window of time to +// read the interrupt register after lightning is detected, and 1.5 after +// disturber. +uint8_t AS3935Component::read_interrupt_register_() { + // A 2ms delay is added to allow for the memory register to be populated + // after the interrupt pin goes HIGH. See "Interrupt Management" in + // datasheet. + ESP_LOGV(TAG, "Calling read_interrupt_register_"); + delay(2); + return this->read_register_(INT_MASK_ANT, INT_MASK); +} + +// REG0x02, bit [6], manufacturer default: 1. +// This register clears the number of lightning strikes that has been read in +// the last 15 minute block. +void AS3935Component::clear_statistics_() { + // Write high, then low, then high to clear. + ESP_LOGV(TAG, "Calling clear_statistics_"); + this->write_register(LIGHTNING_REG, (1 << 6), 1, 6); + this->write_register(LIGHTNING_REG, (1 << 6), 0, 6); + this->write_register(LIGHTNING_REG, (1 << 6), 1, 6); +} + +// REG0x07, bit [5:0], manufacturer default: 0. +// This register holds the distance to the front of the storm and not the +// distance to a lightning strike. +uint8_t AS3935Component::get_distance_to_storm_() { + ESP_LOGV(TAG, "Calling get_distance_to_storm_"); + return this->read_register_(DISTANCE, DISTANCE_MASK); +} + +uint32_t AS3935Component::get_lightning_energy_() { + ESP_LOGV(TAG, "Calling get_lightning_energy_"); + uint32_t pure_light = 0; // Variable for lightning energy which is just a pure number. + uint32_t temp = 0; + // Temp variable for lightning energy. + temp = this->read_register_(ENERGY_LIGHT_MMSB, ENERGY_MASK); + // Temporary Value is large enough to handle a shift of 16 bits. + pure_light = temp << 16; + temp = this->read_register(ENERGY_LIGHT_MSB); + // Temporary value is large enough to handle a shift of 8 bits. + pure_light |= temp << 8; + // No shift here, directly OR'ed into pure_light variable. + temp = this->read_register(ENERGY_LIGHT_LSB); + pure_light |= temp; + return pure_light; +} + +uint8_t AS3935Component::read_register_(uint8_t reg, uint8_t mask) { + uint8_t value = this->read_register(reg); + + value &= (~mask); + return value; +} + +void ICACHE_RAM_ATTR AS3935ComponentStore::gpio_intr(AS3935ComponentStore *arg) { arg->interrupt = true; } + +} // namespace as3935_base +} // namespace esphome diff --git a/esphome/components/as3935_base/as3935_base.h b/esphome/components/as3935_base/as3935_base.h new file mode 100644 index 0000000000..f11a589d50 --- /dev/null +++ b/esphome/components/as3935_base/as3935_base.h @@ -0,0 +1,102 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace as3935_base { + +enum AS3935RegisterNames { + AFE_GAIN = 0x00, + THRESHOLD, + LIGHTNING_REG, + INT_MASK_ANT, + ENERGY_LIGHT_LSB, + ENERGY_LIGHT_MSB, + ENERGY_LIGHT_MMSB, + DISTANCE, + FREQ_DISP_IRQ, + CALIB_TRCO = 0x3A, + CALIB_SRCO = 0x3B, + DEFAULT_RESET = 0x3C, + CALIB_RCO = 0x3D +}; + +enum AS3935RegisterMasks { + GAIN_MASK = 0x3E, + SPIKE_MASK = 0xF, + IO_MASK = 0xC1, + DISTANCE_MASK = 0xC0, + INT_MASK = 0xF0, + THRESH_MASK = 0x0F, + R_SPIKE_MASK = 0xF0, + ENERGY_MASK = 0xF0, + CAP_MASK = 0xF0, + LIGHT_MASK = 0xCF, + DISTURB_MASK = 0xDF, + NOISE_FLOOR_MASK = 0x70, + OSC_MASK = 0xE0, + CALIB_MASK = 0x7F, + DIV_MASK = 0x3F +}; + +enum AS3935Values { + AS3935_ADDR = 0x03, + INDOOR = 0x12, + OUTDOOR = 0xE, + LIGHTNING_INT = 0x08, + DISTURBER_INT = 0x04, + NOISE_INT = 0x01 +}; + +/// Store data in a class that doesn't use multiple-inheritance (vtables in flash) +struct AS3935ComponentStore { + volatile bool interrupt; + + ISRInternalGPIOPin *pin; + static void gpio_intr(AS3935ComponentStore *arg); +}; + +class AS3935Component : public Component { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + void loop() override; + + void set_pin(GPIOPin *pin) { pin_ = pin; } + void set_distance_sensor(sensor::Sensor *distance_sensor) { distance_sensor_ = distance_sensor; } + void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; } + void set_thunder_alert_binary_sensor(binary_sensor::BinarySensor *thunder_alert_binary_sensor) { + thunder_alert_binary_sensor_ = thunder_alert_binary_sensor; + } + void set_indoor(bool indoor); + void set_watchdog_threshold(uint8_t sensitivity); + void set_noise_level(uint8_t floor); + void set_spike_rejection(uint8_t spike_sensitivity); + void set_lightning_threshold(uint8_t strikes); + void set_mask_disturber(bool enabled); + void set_div_ratio(uint8_t div_ratio); + void set_cap(uint8_t eight_pico_farad); + + protected: + uint8_t read_interrupt_register_(); + void clear_statistics_(); + uint8_t get_distance_to_storm_(); + uint32_t get_lightning_energy_(); + + virtual uint8_t read_register(uint8_t reg) = 0; + uint8_t read_register_(uint8_t reg, uint8_t mask); + + virtual void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) = 0; + + sensor::Sensor *distance_sensor_; + sensor::Sensor *energy_sensor_; + binary_sensor::BinarySensor *thunder_alert_binary_sensor_; + GPIOPin *pin_; + AS3935ComponentStore store_; +}; + +} // namespace as3935_base +} // namespace esphome diff --git a/esphome/components/as3935_base/binary_sensor.py b/esphome/components/as3935_base/binary_sensor.py new file mode 100644 index 0000000000..8bef1696d1 --- /dev/null +++ b/esphome/components/as3935_base/binary_sensor.py @@ -0,0 +1,16 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from . import AS3935, CONF_AS3935_ID + +DEPENDENCIES = ['as3935_base'] + +CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({ + cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935), +}) + + +def to_code(config): + hub = yield cg.get_variable(config[CONF_AS3935_ID]) + var = yield binary_sensor.new_binary_sensor(config) + cg.add(hub.set_thunder_alert_binary_sensor(var)) diff --git a/esphome/components/as3935_base/sensor.py b/esphome/components/as3935_base/sensor.py new file mode 100644 index 0000000000..64df519035 --- /dev/null +++ b/esphome/components/as3935_base/sensor.py @@ -0,0 +1,30 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import CONF_DISTANCE, CONF_LIGHTNING_ENERGY, \ + UNIT_KILOMETER, UNIT_EMPTY, ICON_SIGNAL_DISTANCE_VARIANT, ICON_FLASH +from . import AS3935, CONF_AS3935_ID + +DEPENDENCIES = ['as3935_base'] + +CONFIG_SCHEMA = cv.Schema({ + cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935), + cv.Optional(CONF_DISTANCE): + sensor.sensor_schema(UNIT_KILOMETER, ICON_SIGNAL_DISTANCE_VARIANT, 1), + cv.Optional(CONF_LIGHTNING_ENERGY): + sensor.sensor_schema(UNIT_EMPTY, ICON_FLASH, 1), +}).extend(cv.COMPONENT_SCHEMA) + + +def to_code(config): + hub = yield cg.get_variable(config[CONF_AS3935_ID]) + + if CONF_DISTANCE in config: + conf = config[CONF_DISTANCE] + distance_sensor = yield sensor.new_sensor(conf) + cg.add(hub.set_distance_sensor(distance_sensor)) + + if CONF_LIGHTNING_ENERGY in config: + conf = config[CONF_LIGHTNING_ENERGY] + lightning_energy_sensor = yield sensor.new_sensor(conf) + cg.add(hub.set_distance_sensor(lightning_energy_sensor)) diff --git a/esphome/components/as3935_i2c/__init__.py b/esphome/components/as3935_i2c/__init__.py new file mode 100644 index 0000000000..a474ad19e5 --- /dev/null +++ b/esphome/components/as3935_i2c/__init__.py @@ -0,0 +1,20 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import as3935_base, i2c +from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES + +AUTO_LOAD = ['as3935_base'] +DEPENDENCIES = ['i2c'] + +as3935_i2c_ns = cg.esphome_ns.namespace('as3935_i2c') +I2CAS3935 = as3935_i2c_ns.class_('I2CAS3935Component', as3935_base.AS3935, i2c.I2CDevice) + +CONFIG_SCHEMA = cv.All(as3935_base.AS3935_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(I2CAS3935), +}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x03))) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield as3935_base.setup_as3935(var, config) + yield i2c.register_i2c_device(var, config) diff --git a/esphome/components/as3935_i2c/as3935_i2c.cpp b/esphome/components/as3935_i2c/as3935_i2c.cpp new file mode 100644 index 0000000000..7792bd3e29 --- /dev/null +++ b/esphome/components/as3935_i2c/as3935_i2c.cpp @@ -0,0 +1,36 @@ +#include "as3935_i2c.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace as3935_i2c { + +static const char *TAG = "as3935_i2c"; + +void I2CAS3935Component::write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_pos) { + uint8_t write_reg; + if (!this->read_byte(reg, &write_reg)) { + this->mark_failed(); + ESP_LOGW(TAG, "read_byte failed - increase log level for more details!"); + return; + } + + write_reg &= (~mask); + write_reg |= (bits << start_pos); + + if (!this->write_byte(reg, write_reg)) { + ESP_LOGW(TAG, "write_byte failed - increase log level for more details!"); + return; + } +} + +uint8_t I2CAS3935Component::read_register(uint8_t reg) { + uint8_t value; + if (!this->read_byte(reg, &value, 2)) { + ESP_LOGW(TAG, "Read failed!"); + return 0; + } + return value; +} + +} // namespace as3935_i2c +} // namespace esphome diff --git a/esphome/components/as3935_i2c/as3935_i2c.h b/esphome/components/as3935_i2c/as3935_i2c.h new file mode 100644 index 0000000000..93cedf537b --- /dev/null +++ b/esphome/components/as3935_i2c/as3935_i2c.h @@ -0,0 +1,21 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/as3935_base/as3935_base.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace as3935_i2c { + +class I2CAS3935Component : public as3935_base::AS3935Component, public i2c::I2CDevice { + public: + + protected: + void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) override; + uint8_t read_register(uint8_t reg) override; +}; + +} // namespace as3935_i2c +} // namespace esphome diff --git a/esphome/components/as3935_spi/__init__.py b/esphome/components/as3935_spi/__init__.py new file mode 100644 index 0000000000..c1daf58150 --- /dev/null +++ b/esphome/components/as3935_spi/__init__.py @@ -0,0 +1,20 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import as3935_base, spi +from esphome.const import CONF_ID + +AUTO_LOAD = ['as3935_base'] +DEPENDENCIES = ['spi'] + +as3935_spi_ns = cg.esphome_ns.namespace('as3935_spi') +SPIAS3935 = as3935_spi_ns.class_('SPIAS3935Component', as3935_base.AS3935, spi.SPIDevice) + +CONFIG_SCHEMA = cv.All(as3935_base.AS3935_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(SPIAS3935) +}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA)) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield as3935_base.setup_as3935(var, config) + yield spi.register_spi_device(var, config) diff --git a/esphome/components/as3935_spi/as3935_spi.cpp b/esphome/components/as3935_spi/as3935_spi.cpp new file mode 100644 index 0000000000..97847de080 --- /dev/null +++ b/esphome/components/as3935_spi/as3935_spi.cpp @@ -0,0 +1,49 @@ +#include "as3935_spi.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace as3935_spi { + +static const char *TAG = "as3935_spi"; + +void SPIAS3935Component::setup() { + ESP_LOGI(TAG, "SPIAS3935Component setup started!"); + this->spi_setup(); + ESP_LOGI(TAG, "SPI setup finished!"); + AS3935Component::setup(); + +} + +void SPIAS3935Component::dump_config() { + AS3935Component::dump_config(); + LOG_PIN(" CS Pin: ", this->cs_); +} + +void SPIAS3935Component::write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_pos) { + uint8_t write_reg = this->read_register(reg); + + write_reg &= (~mask); + write_reg |= (bits << start_pos); + + this->enable(); + this->write_byte(reg); + this->write_byte(write_reg); + this->disable(); +} + +uint8_t SPIAS3935Component::read_register(uint8_t reg) { + uint8_t value = 0; + this->enable(); + this->write_byte(reg |= SPI_READ_M); + value = this->read_byte(); + // According to datsheet, the chip select must be written HIGH, LOW, HIGH + // to correctly end the READ command. + this->cs_->digital_write(true); + this->cs_->digital_write(false); + this->disable(); + ESP_LOGV(TAG, "read_register_: %d", value); + return value; +} + +} // namespace as3935_spi +} // namespace esphome diff --git a/esphome/components/as3935_spi/as3935_spi.h b/esphome/components/as3935_spi/as3935_spi.h new file mode 100644 index 0000000000..ec80d76821 --- /dev/null +++ b/esphome/components/as3935_spi/as3935_spi.h @@ -0,0 +1,27 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/as3935_base/as3935_base.h" +#include "esphome/components/spi/spi.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace as3935_spi { + +enum AS3935RegisterMasks { SPI_READ_M = 0x40 }; + +class SPIAS3935Component : public as3935_base::AS3935Component, + public spi::SPIDevice { + public: + void setup() override; + void dump_config() override; + + protected: + void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) override; + uint8_t read_register(uint8_t reg) override; +}; + +} // namespace as3935_spi +} // namespace esphome diff --git a/esphome/components/i2c/i2c.cpp b/esphome/components/i2c/i2c.cpp index 3fa9d2c37a..b93c7d6053 100644 --- a/esphome/components/i2c/i2c.cpp +++ b/esphome/components/i2c/i2c.cpp @@ -32,7 +32,7 @@ void I2CComponent::dump_config() { if (this->scan_) { ESP_LOGI(TAG, "Scanning i2c bus for active devices..."); uint8_t found = 0; - for (uint8_t address = 8; address < 120; address++) { + for (uint8_t address = 1; address < 120; address++) { this->wire_->beginTransmission(address); uint8_t error = this->wire_->endTransmission(); diff --git a/esphome/const.py b/esphome/const.py index 3811d5b9cf..86a0a43bdc 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -63,6 +63,7 @@ CONF_BUSY_PIN = 'busy_pin' CONF_BUS_VOLTAGE = 'bus_voltage' CONF_CALIBRATE_LINEAR = 'calibrate_linear' CONF_CALIBRATION = 'calibration' +CONF_CAP = 'cap' CONF_CARRIER_DUTY_PERCENT = 'carrier_duty_percent' CONF_CARRIER_FREQUENCY = 'carrier_frequency' CONF_CHANGE_MODE_EVERY = 'change_mode_every' @@ -119,8 +120,10 @@ CONF_DIMENSIONS = 'dimensions' CONF_DIRECTION = 'direction' CONF_DIR_PIN = 'dir_pin' CONF_DISCOVERY = 'discovery' +CONF_DISTANCE = 'distance' CONF_DISCOVERY_PREFIX = 'discovery_prefix' CONF_DISCOVERY_RETAIN = 'discovery_retain' +CONF_DIV_RATIO = 'div_ratio' CONF_DNS1 = 'dns1' CONF_DNS2 = 'dns2' CONF_DOMAIN = 'domain' @@ -183,6 +186,7 @@ CONF_IIR_FILTER = 'iir_filter' CONF_ILLUMINANCE = 'illuminance' CONF_INCLUDES = 'includes' CONF_INDEX = 'index' +CONF_INDOOR = 'indoor' CONF_INITIAL_MODE = 'initial_mode' CONF_INITIAL_VALUE = 'initial_value' CONF_INTEGRATION_TIME = 'integration_time' @@ -204,6 +208,8 @@ CONF_LEVEL = 'level' CONF_LG = 'lg' CONF_LIBRARIES = 'libraries' CONF_LIGHT = 'light' +CONF_LIGHTNING_ENERGY = 'lightning_energy' +CONF_LIGHTNING_THRESHOLD = 'lightning_threshold' CONF_LOADED_INTEGRATIONS = 'loaded_integrations' CONF_LOCAL = 'local' CONF_LOGGER = 'logger' @@ -214,6 +220,7 @@ CONF_LOW_VOLTAGE_REFERENCE = 'low_voltage_reference' CONF_MAC_ADDRESS = 'mac_address' CONF_MAKE_ID = 'make_id' CONF_MANUAL_IP = 'manual_ip' +CONF_MASK_DISTURBER = 'mask_disturber' CONF_MAX_CURRENT = 'max_current' CONF_MAX_DURATION = 'max_duration' CONF_MAX_LENGTH = 'max_length' @@ -248,6 +255,7 @@ CONF_NAME = 'name' CONF_NBITS = 'nbits' CONF_NEC = 'nec' CONF_NETWORKS = 'networks' +CONF_NOISE_LEVEL = 'noise_level' CONF_NUMBER = 'number' CONF_NUM_ATTEMPTS = 'num_attempts' CONF_NUM_CHANNELS = 'num_channels' @@ -383,6 +391,7 @@ CONF_SPEED = 'speed' CONF_SPEED_COMMAND_TOPIC = 'speed_command_topic' CONF_SPEED_STATE_TOPIC = 'speed_state_topic' CONF_SPI_ID = 'spi_id' +CONF_SPIKE_REJECTION = 'spike_rejection' CONF_SSID = 'ssid' CONF_SSL_FINGERPRINTS = 'ssl_fingerprints' CONF_STATE = 'state' @@ -449,6 +458,7 @@ CONF_WAIT_UNTIL = 'wait_until' CONF_WAKEUP_PIN = 'wakeup_pin' CONF_WARM_WHITE = 'warm_white' CONF_WARM_WHITE_COLOR_TEMPERATURE = 'warm_white_color_temperature' +CONF_WATCHDOG_THRESHOLD = 'watchdog_threshold' CONF_WHILE = 'while' CONF_WHITE = 'white' CONF_WIDTH = 'width' @@ -482,7 +492,8 @@ ICON_RESTART = 'mdi:restart' ICON_ROTATE_RIGHT = 'mdi:rotate-right' ICON_SCALE = 'mdi:scale' ICON_SCREEN_ROTATION = 'mdi:screen-rotation' -ICON_SIGNAL = 'mdi:signal' +ICON_SIGNAL = 'mdi: signal-distance-variant' +ICON_SIGNAL_DISTANCE_VARIANT = 'mdi:signal' ICON_SIGN_DIRECTION = 'mdi:sign-direction' ICON_WEATHER_SUNSET = 'mdi:weather-sunset' ICON_WEATHER_SUNSET_DOWN = 'mdi:weather-sunset-down' @@ -502,6 +513,7 @@ UNIT_EMPTY = '' UNIT_HZ = 'hz' UNIT_HECTOPASCAL = 'hPa' UNIT_KELVIN = 'K' +UNIT_KILOMETER = 'km' UNIT_KILOMETER_PER_HOUR = 'km/h' UNIT_LUX = 'lx' UNIT_METER = 'm' diff --git a/script/quicklint b/script/quicklint index 06c31d519d..e391ca3276 100755 --- a/script/quicklint +++ b/script/quicklint @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -e diff --git a/script/setup b/script/setup index a65eb23a63..b6cff39f0c 100755 --- a/script/setup +++ b/script/setup @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # Set up ESPHome dev environment set -e diff --git a/tests/test1.yaml b/tests/test1.yaml index 66320f876f..9723daed09 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -171,6 +171,10 @@ ads1115: dallas: pin: GPIO23 +as3935_spi: + cs_pin: GPIO12 + pin: GPIO13 + sensor: - platform: adc pin: A0 @@ -595,7 +599,11 @@ sensor: name: "ZyAura Temperature" humidity: name: "ZyAura Humidity" - + - platform: as3935_base + lightning_energy: + name: "Lightning Energy" + distance: + name: "Distance Storm" esp32_touch: setup_mode: False @@ -730,6 +738,8 @@ binary_sensor: 3700, -2263, 1712, -4254, 1711, -4249, 1715, -2266, 1710, -2267, 1709, -2265, 3704, -4250, 1712, -4254, 3700, -2260, 1714, -2265, 1712, -2262, 1714, -2267, 1709] + - platform: as3935_base + name: "Storm Alert" pca9685: frequency: 500 diff --git a/tests/test2.yaml b/tests/test2.yaml index e3a9b0da85..1164ebfe4f 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -50,6 +50,10 @@ deep_sleep: run_duration: 20s sleep_duration: 50s +as3935_i2c: + pin: GPIO12 + + sensor: - platform: ble_rssi mac_address: AC:37:43:77:5F:4C @@ -125,6 +129,11 @@ sensor: - platform: homeassistant entity_id: sensor.hello_world id: ha_hello_world + - platform: as3935_base + lightning_energy: + name: "Lightning Energy" + distance: + name: "Distance Storm" time: - platform: homeassistant @@ -163,6 +172,8 @@ binary_sensor: - platform: homeassistant entity_id: binary_sensor.hello_world id: ha_hello_world_binary + - platform: as3935_base + name: "Storm Alert" remote_receiver: pin: GPIO32