mirror of
https://github.com/nuttytree/ESPHome-Devices.git
synced 2024-08-30 18:12:19 +00:00
Energy monitoring fixes (#17)
* Fix energy monitoring for feit dimmers * More energy reporting fixes/updates * More energy monitoring updates * Include missed readme update * Final power monitoring updates Co-authored-by: Chris Nussbaum <chris.nussbaum@protolabs.com>
This commit is contained in:
parent
3fdca0bf0f
commit
adc77d67d9
16
README.md
16
README.md
@ -10,14 +10,20 @@ Home Assistant is open source home automation that puts local control and privac
|
||||
|
||||
|
||||
## Custom Components
|
||||
### Binary Light With Power
|
||||
This an enhanced version of the standard [binary light](https://esphome.io/components/light/binary.html) component that adds an option to include a sensor to report current power usage based on a configured wattage of the light(s) it controls. More details on how to use this component are available [here](./components/binary_light_with_power/README.md).
|
||||
|
||||
### GPIO Light With Power
|
||||
This an enhanced version of the standard [gpio switch](https://esphome.io/components/switch/gpio.html) component that adds an option to include a sensor to report current power usage based on a configured wattage of the device(s) it controls. More details on how to use this component are available [here](./components/gpio_switch_with_power/README.md).
|
||||
|
||||
### Tuya
|
||||
This is a copy of the standard Tuya component with a couple of fixes/tweaks that are still getting hashed out in the main branch of ESPHome that are needed to get my custom Tuya Light Plus component to work reliably. Hopefully I can remove this component soon.
|
||||
|
||||
### Tuya Light Plus
|
||||
This an enhanced version of the standard [Tuya](https://esphome.io/components/light/tuya.html) light component that adds a bunch of extra features. I use this component with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) but it will likely work with other Tuya dimmers. More details on features and how to use this component are available [here](./components/tuya_light_plus/README.md).
|
||||
|
||||
### Tuya Dimmer as Fan
|
||||
This a modified version of the Tuya fan component I use with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) (but it will likely work with other Tuya dimmers) to control bathroom fans. The major change from the standard Tuya fan component (other than removing options for speed, oscillation, and direction) is adding a function to always change the dimmer back to the maximum "brightness" effectively making this only an on/off device. Details on how to use this component are available [here](./components/tuya_dimmer_as_fan/README.md).
|
||||
This a modified version of the [Tuya fan](https://esphome.io/components/fan/tuya.html) component I use with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) (but it will likely work with other Tuya dimmers) to control bathroom fans and adds several features. I created this component because I couldn't find a regular on/off switch with the same look and feel as the Feit dimmers so I decided to use the Feit dimmers but use this component to prevent "dimming" the fan. More details on features and how to use this component are available [here](./components/tuya_dimmer_as_fan/README.md).
|
||||
|
||||
### Tuya Light Plus
|
||||
This an enhanced version of the standard [Tuya light](https://esphome.io/components/light/tuya.html) component that adds a bunch of extra features. I use this component with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) but it will likely work with other Tuya dimmers. More details on features and how to use this component are available [here](./components/tuya_light_plus/README.md).
|
||||
|
||||
### ESPSense
|
||||
This excellent component is not mine and doesn't live in this repository but most of my devices are using it so I felt it was worthy of a mention here. More details are available [here](https://github.com/cbpowell/ESPSense).
|
||||
@ -55,7 +61,7 @@ This project was one of the first projects I have done that I would call woodwor
|
||||
I plan to use dimmer switches for anything that is dimmable just for consistency and you never know when you might want to have the ability to dim a light. However there are times when a dimmer isn't an option.
|
||||
|
||||
### [SANA Dual Switch](https://www.amazon.com/gp/product/B07QC5ZCHP/ref=ppx_yo_dt_b_asin_title_o03_s01?ie=UTF8&th=1)
|
||||
My basement bathroom has 4 devices (main light, fan, shower light, heat lamps) but only 2 single gang boxes (and not enough room to swith to dual gang) so these were a perfect fit. The prices is right, the buttons feel solid, and I was able to flash them using [Tuya-Convert](https://github.com/ct-Open-Source/tuya-convert). They do seem to have corners that are squarer then typical so I had a little bit of trouble getting a standard cover to fit but nothing I couldn't fix with a file.
|
||||
My basement bathroom has 4 devices (main light, fan, shower light, and heat lamps) but only 2 single gang boxes (and not enough room to swith to dual gang) so these were a perfect fit. The price is right, the buttons feel solid, and I was able to flash them using [Tuya-Convert](https://github.com/ct-Open-Source/tuya-convert). They do seem to have corners that are squarer then typical so I had a little bit of trouble getting a standard cover to fit but nothing I couldn't fix with a file.
|
||||
* [Basement Bathroom Light and Fan](./devices/basement_bathroom_light_fan.yaml)
|
||||
* [Basement Bathroom Shower Light and Heater](./devices/basement_bathroom_shower_light_heater.yaml)
|
||||
|
||||
|
40
components/binary_light_with_power/README.md
Normal file
40
components/binary_light_with_power/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Binary Light With Power Component
|
||||
## Overview
|
||||
This an enhanced version of the standard [binary light](https://esphome.io/components/light/binary.html) component that adds an option to include a sensor to report current power usage based on a configured wattage of the light(s) it controls.
|
||||
|
||||
|
||||
## Setup
|
||||
Using the [External Components](https://esphome.io/components/external_components.html) feature in ESPHome you can add this component to your devices directly from my GitHub repo.
|
||||
```yaml
|
||||
external_components:
|
||||
- source: github://nuttytree/esphome
|
||||
components: [ binary_light_with_power ]
|
||||
```
|
||||
|
||||
Like the standard binary light component you need to have an [output](https://esphome.io/components/output.html).
|
||||
```yaml
|
||||
output:
|
||||
- platform: gpio
|
||||
id: my_light_output
|
||||
pin: 13
|
||||
```
|
||||
|
||||
Add and configure the Binary Light With Power Component
|
||||
```yaml
|
||||
light:
|
||||
- platform: binary_light_with_power
|
||||
id: my_light
|
||||
name: My Light
|
||||
output: my_light_output
|
||||
power:
|
||||
id: my_light_power
|
||||
name: My Light Power
|
||||
light_wattage: 48.0
|
||||
update_interval: 60s
|
||||
```
|
||||
|
||||
## Configuration Variables (In addition to the standard variables)
|
||||
* power.id (Optional, string) Manually specify the power sensor ID used for code generation.
|
||||
* power.name (Optional, string) The name for the power sensor
|
||||
* power.light_wattage (Optional, float) The total wattage of the light(s) controled by this dimmer
|
||||
* power.update_interval (Optional, Time, default: 60s) Amount of time between updates of the power value while on.
|
0
components/binary_light_with_power/__init__.py
Normal file
0
components/binary_light_with_power/__init__.py
Normal file
@ -0,0 +1,37 @@
|
||||
#include "binary_light_with_power.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace binary_power {
|
||||
|
||||
light::LightTraits BinaryLightWithPower::get_traits() {
|
||||
auto traits = light::LightTraits();
|
||||
// TODO: Enable this with the 1.21.x version of ESPHome
|
||||
// traits.set_supported_color_modes({light::ColorMode::ON_OFF});
|
||||
return traits;
|
||||
}
|
||||
|
||||
void BinaryLightWithPower::write_state(light::LightState *state) {
|
||||
bool binary;
|
||||
state->current_values_as_binary(&binary);
|
||||
this->state_ = binary;
|
||||
if (binary)
|
||||
this->output_->turn_on();
|
||||
else
|
||||
this->output_->turn_off();
|
||||
|
||||
if (this->light_wattage_.has_value() && this->power_sensor_ != nullptr)
|
||||
{
|
||||
float power = this->state_ ? this->light_wattage_.value() : 0.0f;
|
||||
this->power_sensor_->publish_state(power);
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryLightWithPower::update() {
|
||||
if (this->light_wattage_.has_value() && this->power_sensor_ != nullptr && this->state_)
|
||||
{
|
||||
this->power_sensor_->publish_state(this->light_wattage_.value());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace binary_power
|
||||
} // namespace esphome
|
28
components/binary_light_with_power/binary_light_with_power.h
Normal file
28
components/binary_light_with_power/binary_light_with_power.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/light/light_output.h"
|
||||
#include "esphome/components/output/binary_output.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace binary_power {
|
||||
|
||||
class BinaryLightWithPower : public light::LightOutput, public PollingComponent {
|
||||
public:
|
||||
void set_output(output::BinaryOutput *output) { output_ = output; }
|
||||
void set_light_wattage(float light_wattage) { this->light_wattage_ = light_wattage; }
|
||||
void set_power_sensor(sensor::Sensor *power_sensor) { this->power_sensor_ = power_sensor; }
|
||||
light::LightTraits get_traits() override;
|
||||
void write_state(light::LightState *state) override;
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
output::BinaryOutput *output_;
|
||||
bool state_{false};
|
||||
optional<float> light_wattage_{};
|
||||
sensor::Sensor *power_sensor_;
|
||||
};
|
||||
|
||||
} // namespace binary_power
|
||||
} // namespace esphome
|
55
components/binary_light_with_power/light.py
Normal file
55
components/binary_light_with_power/light.py
Normal file
@ -0,0 +1,55 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import core
|
||||
from esphome.components import light, output, sensor
|
||||
from esphome.const import (
|
||||
CONF_OUTPUT_ID,
|
||||
CONF_OUTPUT,
|
||||
CONF_POWER,
|
||||
UNIT_WATT,
|
||||
DEVICE_CLASS_POWER,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
ICON_POWER,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
)
|
||||
|
||||
CONF_LIGHT_WATTAGE = "light_wattage"
|
||||
|
||||
binary_power_ns = cg.esphome_ns.namespace("binary_power")
|
||||
LightWithPower = binary_power_ns.class_("BinaryLightWithPower", light.LightOutput, cg.PollingComponent)
|
||||
|
||||
CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(LightWithPower),
|
||||
cv.Required(CONF_OUTPUT): cv.use_id(output.BinaryOutput),
|
||||
cv.Optional(CONF_POWER): sensor.sensor_schema(
|
||||
unit_of_measurement_=UNIT_WATT,
|
||||
accuracy_decimals_=1,
|
||||
device_class_=DEVICE_CLASS_POWER,
|
||||
state_class_=STATE_CLASS_MEASUREMENT,
|
||||
icon_=ICON_POWER,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_LIGHT_WATTAGE): cv.positive_float,
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.update_interval,
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
||||
await cg.register_component(var, config)
|
||||
await light.register_light(var, config)
|
||||
|
||||
out = await cg.get_variable(config[CONF_OUTPUT])
|
||||
cg.add(var.set_output(out))
|
||||
if CONF_POWER in config:
|
||||
power_config = config[CONF_POWER]
|
||||
power_sensor = await sensor.new_sensor(power_config)
|
||||
cg.add(var.set_light_wattage(power_config[CONF_LIGHT_WATTAGE]))
|
||||
cg.add(var.set_power_sensor(power_sensor))
|
||||
cg.add(var.set_update_interval(power_config[CONF_UPDATE_INTERVAL]))
|
||||
else:
|
||||
cg.add(var.set_update_interval(4294967295)) # uint32_t max
|
32
components/gpio_switch_with_power/README.md
Normal file
32
components/gpio_switch_with_power/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# GPIO Switch With Power Component
|
||||
## Overview
|
||||
This an enhanced version of the standard [gpio switch](https://esphome.io/components/switch/gpio.html) component that adds an option to include a sensor to report current power usage based on a configured wattage of the device(s) it controls.
|
||||
|
||||
|
||||
## Setup
|
||||
Using the [External Components](https://esphome.io/components/external_components.html) feature in ESPHome you can add this component to your devices directly from my GitHub repo.
|
||||
```yaml
|
||||
external_components:
|
||||
- source: github://nuttytree/esphome
|
||||
components: [ gpio_switch_with_power ]
|
||||
```
|
||||
|
||||
Add and configure the GPIO Switch With Power Component
|
||||
```yaml
|
||||
switch:
|
||||
- platform: gpio_switch_with_power
|
||||
id: my_switch
|
||||
name: My Switch
|
||||
pin: 4
|
||||
power:
|
||||
id: my_switch_power
|
||||
name: My Switch Power
|
||||
device_wattage: 48.0
|
||||
update_interval: 60s
|
||||
```
|
||||
|
||||
## Configuration Variables (In addition to the standard variables)
|
||||
* power.id (Optional, string) Manually specify the power sensor ID used for code generation.
|
||||
* power.name (Optional, string) The name for the power sensor
|
||||
* power.device_wattage (Optional, float) The total wattage of the device(s) controled by this dimmer
|
||||
* power.update_interval (Optional, Time, default: 60s) Amount of time between updates of the power value while on.
|
0
components/gpio_switch_with_power/__init__.py
Normal file
0
components/gpio_switch_with_power/__init__.py
Normal file
128
components/gpio_switch_with_power/gpio_switch_with_power.cpp
Normal file
128
components/gpio_switch_with_power/gpio_switch_with_power.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
#include "gpio_switch_with_power.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gpio_power {
|
||||
|
||||
static const char *const TAG = "switch.gpio";
|
||||
|
||||
void GPIOSwitchWithPower::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up GPIO Switch '%s'...", this->name_.c_str());
|
||||
|
||||
bool initial_state = false;
|
||||
switch (this->restore_mode_) {
|
||||
case GPIO_SWITCH_RESTORE_DEFAULT_OFF:
|
||||
initial_state = this->get_initial_state().value_or(false);
|
||||
break;
|
||||
case GPIO_SWITCH_RESTORE_DEFAULT_ON:
|
||||
initial_state = this->get_initial_state().value_or(true);
|
||||
break;
|
||||
case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF:
|
||||
initial_state = !this->get_initial_state().value_or(true);
|
||||
break;
|
||||
case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON:
|
||||
initial_state = !this->get_initial_state().value_or(false);
|
||||
break;
|
||||
case GPIO_SWITCH_ALWAYS_OFF:
|
||||
initial_state = false;
|
||||
break;
|
||||
case GPIO_SWITCH_ALWAYS_ON:
|
||||
initial_state = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// write state before setup
|
||||
if (initial_state)
|
||||
this->turn_on();
|
||||
else
|
||||
this->turn_off();
|
||||
this->pin_->setup();
|
||||
// write after setup again for other IOs
|
||||
if (initial_state)
|
||||
this->turn_on();
|
||||
else
|
||||
this->turn_off();
|
||||
}
|
||||
|
||||
void GPIOSwitchWithPower::dump_config() {
|
||||
LOG_SWITCH("", "GPIO Switch", this);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
const char *restore_mode = "";
|
||||
switch (this->restore_mode_) {
|
||||
case GPIO_SWITCH_RESTORE_DEFAULT_OFF:
|
||||
restore_mode = "Restore (Defaults to OFF)";
|
||||
break;
|
||||
case GPIO_SWITCH_RESTORE_DEFAULT_ON:
|
||||
restore_mode = "Restore (Defaults to ON)";
|
||||
break;
|
||||
case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON:
|
||||
restore_mode = "Restore inverted (Defaults to ON)";
|
||||
break;
|
||||
case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF:
|
||||
restore_mode = "Restore inverted (Defaults to OFF)";
|
||||
break;
|
||||
case GPIO_SWITCH_ALWAYS_OFF:
|
||||
restore_mode = "Always OFF";
|
||||
break;
|
||||
case GPIO_SWITCH_ALWAYS_ON:
|
||||
restore_mode = "Always ON";
|
||||
break;
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Restore Mode: %s", restore_mode);
|
||||
if (!this->interlock_.empty()) {
|
||||
ESP_LOGCONFIG(TAG, " Interlocks:");
|
||||
for (auto *lock : this->interlock_) {
|
||||
if (lock == this)
|
||||
continue;
|
||||
ESP_LOGCONFIG(TAG, " %s", lock->get_name().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPIOSwitchWithPower::update() {
|
||||
if (this->device_wattage_.has_value() && this->power_sensor_ != nullptr && this->state)
|
||||
{
|
||||
this->power_sensor_->publish_state(this->device_wattage_.value());
|
||||
}
|
||||
}
|
||||
|
||||
void GPIOSwitchWithPower::write_state(bool state) {
|
||||
if (state != this->inverted_) {
|
||||
// Turning ON, check interlocking
|
||||
|
||||
bool found = false;
|
||||
for (auto *lock : this->interlock_) {
|
||||
if (lock == this)
|
||||
continue;
|
||||
|
||||
if (lock->state) {
|
||||
lock->turn_off();
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found && this->interlock_wait_time_ != 0) {
|
||||
this->set_timeout("interlock", this->interlock_wait_time_, [this, state] {
|
||||
// Don't write directly, call the function again
|
||||
// (some other switch may have changed state while we were waiting)
|
||||
this->write_state(state);
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else if (this->interlock_wait_time_ != 0) {
|
||||
// If we are switched off during the interlock wait time, cancel any pending
|
||||
// re-activations
|
||||
this->cancel_timeout("interlock");
|
||||
}
|
||||
|
||||
this->pin_->digital_write(state);
|
||||
this->publish_state(state);
|
||||
|
||||
if (this->device_wattage_.has_value() && this->power_sensor_ != nullptr)
|
||||
{
|
||||
float power = state ? this->device_wattage_.value() : 0.0f;
|
||||
this->power_sensor_->publish_state(power);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gpio_power
|
||||
} // namespace esphome
|
44
components/gpio_switch_with_power/gpio_switch_with_power.h
Normal file
44
components/gpio_switch_with_power/gpio_switch_with_power.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/switch/switch.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gpio_power {
|
||||
|
||||
enum GPIOSwitchRestoreMode {
|
||||
GPIO_SWITCH_RESTORE_DEFAULT_OFF,
|
||||
GPIO_SWITCH_RESTORE_DEFAULT_ON,
|
||||
GPIO_SWITCH_ALWAYS_OFF,
|
||||
GPIO_SWITCH_ALWAYS_ON,
|
||||
GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF,
|
||||
GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON,
|
||||
};
|
||||
|
||||
class GPIOSwitchWithPower : public switch_::Switch, public PollingComponent {
|
||||
public:
|
||||
void set_pin(GPIOPin *pin) { pin_ = pin; }
|
||||
void set_restore_mode(GPIOSwitchRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
|
||||
void set_interlock(const std::vector<Switch *> &interlock) { this->interlock_ = interlock; }
|
||||
void set_interlock_wait_time(uint32_t interlock_wait_time) { interlock_wait_time_ = interlock_wait_time; }
|
||||
void set_device_wattage(float device_wattage) { this->device_wattage_ = device_wattage; }
|
||||
void set_power_sensor(sensor::Sensor *power_sensor) { this->power_sensor_ = power_sensor; }
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
void write_state(bool state) override;
|
||||
|
||||
GPIOPin *pin_;
|
||||
GPIOSwitchRestoreMode restore_mode_{GPIO_SWITCH_RESTORE_DEFAULT_OFF};
|
||||
std::vector<Switch *> interlock_;
|
||||
uint32_t interlock_wait_time_{0};
|
||||
optional<float> device_wattage_{};
|
||||
sensor::Sensor *power_sensor_;
|
||||
};
|
||||
|
||||
} // namespace gpio_power
|
||||
} // namespace esphome
|
86
components/gpio_switch_with_power/switch.py
Normal file
86
components/gpio_switch_with_power/switch.py
Normal file
@ -0,0 +1,86 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import switch, sensor
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_INTERLOCK,
|
||||
CONF_PIN,
|
||||
CONF_RESTORE_MODE,
|
||||
CONF_POWER,
|
||||
UNIT_WATT,
|
||||
DEVICE_CLASS_POWER,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
ICON_POWER,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
)
|
||||
|
||||
gpio_power_ns = cg.esphome_ns.namespace("gpio_power")
|
||||
GPIOSwitchWithPower = gpio_power_ns.class_("GPIOSwitchWithPower", switch.Switch, cg.PollingComponent)
|
||||
GPIOSwitchRestoreMode = gpio_power_ns.enum("GPIOSwitchRestoreMode")
|
||||
|
||||
RESTORE_MODES = {
|
||||
"RESTORE_DEFAULT_OFF": GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_DEFAULT_OFF,
|
||||
"RESTORE_DEFAULT_ON": GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_DEFAULT_ON,
|
||||
"ALWAYS_OFF": GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_OFF,
|
||||
"ALWAYS_ON": GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_ON,
|
||||
"RESTORE_INVERTED_DEFAULT_OFF": GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF,
|
||||
"RESTORE_INVERTED_DEFAULT_ON": GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON,
|
||||
}
|
||||
|
||||
CONF_INTERLOCK_WAIT_TIME = "interlock_wait_time"
|
||||
CONF_DEVICE_WATTAGE = "device_wattage"
|
||||
|
||||
CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(GPIOSwitchWithPower),
|
||||
cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Optional(CONF_RESTORE_MODE, default="RESTORE_DEFAULT_OFF"): cv.enum(
|
||||
RESTORE_MODES, upper=True, space="_"
|
||||
),
|
||||
cv.Optional(CONF_INTERLOCK): cv.ensure_list(cv.use_id(switch.Switch)),
|
||||
cv.Optional(
|
||||
CONF_INTERLOCK_WAIT_TIME, default="0ms"
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_POWER): sensor.sensor_schema(
|
||||
unit_of_measurement_=UNIT_WATT,
|
||||
accuracy_decimals_=1,
|
||||
device_class_=DEVICE_CLASS_POWER,
|
||||
state_class_=STATE_CLASS_MEASUREMENT,
|
||||
icon_=ICON_POWER,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_DEVICE_WATTAGE): cv.positive_float,
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.update_interval,
|
||||
}
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await switch.register_switch(var, config)
|
||||
|
||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||
cg.add(var.set_pin(pin))
|
||||
|
||||
cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
|
||||
if CONF_INTERLOCK in config:
|
||||
interlock = []
|
||||
for it in config[CONF_INTERLOCK]:
|
||||
lock = await cg.get_variable(it)
|
||||
interlock.append(lock)
|
||||
cg.add(var.set_interlock(interlock))
|
||||
cg.add(var.set_interlock_wait_time(config[CONF_INTERLOCK_WAIT_TIME]))
|
||||
|
||||
if CONF_POWER in config:
|
||||
power_config = config[CONF_POWER]
|
||||
power_sensor = await sensor.new_sensor(power_config)
|
||||
cg.add(var.set_device_wattage(power_config[CONF_DEVICE_WATTAGE]))
|
||||
cg.add(var.set_power_sensor(power_sensor))
|
||||
cg.add(var.set_update_interval(power_config[CONF_UPDATE_INTERVAL]))
|
||||
else:
|
||||
cg.add(var.set_update_interval(4294967295)) # uint32_t max
|
0
components/total_daily_energy/__init__.py
Normal file
0
components/total_daily_energy/__init__.py
Normal file
65
components/total_daily_energy/sensor.py
Normal file
65
components/total_daily_energy/sensor.py
Normal file
@ -0,0 +1,65 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, time
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_TIME_ID,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
LAST_RESET_TYPE_AUTO,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["time"]
|
||||
|
||||
CONF_POWER_ID = "power_id"
|
||||
CONF_MIN_SAVE_INTERVAL = "min_save_interval"
|
||||
CONF_TOTAL_DAILY_ENERGY_METHOD = "method"
|
||||
total_daily_energy_ns = cg.esphome_ns.namespace("total_daily_energy")
|
||||
TotalDailyEnergyMethod = total_daily_energy_ns.enum("TotalDailyEnergyMethod")
|
||||
TOTAL_DAILY_ENERGY_METHODS = {
|
||||
"trapezoid": TotalDailyEnergyMethod.TOTAL_DAILY_ENERGY_METHOD_TRAPEZOID,
|
||||
"left": TotalDailyEnergyMethod.TOTAL_DAILY_ENERGY_METHOD_LEFT,
|
||||
"right": TotalDailyEnergyMethod.TOTAL_DAILY_ENERGY_METHOD_RIGHT,
|
||||
}
|
||||
TotalDailyEnergy = total_daily_energy_ns.class_(
|
||||
"TotalDailyEnergy", sensor.Sensor, cg.Component
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(
|
||||
accuracy_decimals_=0,
|
||||
device_class_=DEVICE_CLASS_ENERGY,
|
||||
state_class_=STATE_CLASS_MEASUREMENT,
|
||||
last_reset_type_=LAST_RESET_TYPE_AUTO,
|
||||
icon_="",
|
||||
unit_of_measurement_="",
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(TotalDailyEnergy),
|
||||
cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
|
||||
cv.Required(CONF_POWER_ID): cv.use_id(sensor.Sensor),
|
||||
cv.Optional(
|
||||
CONF_MIN_SAVE_INTERVAL, default="0s"
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_TOTAL_DAILY_ENERGY_METHOD, default="left"): cv.enum(
|
||||
TOTAL_DAILY_ENERGY_METHODS, lower=True
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
|
||||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
|
||||
sens = await cg.get_variable(config[CONF_POWER_ID])
|
||||
cg.add(var.set_parent(sens))
|
||||
time_ = await cg.get_variable(config[CONF_TIME_ID])
|
||||
cg.add(var.set_time(time_))
|
||||
cg.add(var.set_min_save_interval(config[CONF_MIN_SAVE_INTERVAL]))
|
||||
cg.add(var.set_method(config[CONF_TOTAL_DAILY_ENERGY_METHOD]))
|
79
components/total_daily_energy/total_daily_energy.cpp
Normal file
79
components/total_daily_energy/total_daily_energy.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "total_daily_energy.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace total_daily_energy {
|
||||
|
||||
static const char *const TAG = "total_daily_energy";
|
||||
|
||||
void TotalDailyEnergy::setup() {
|
||||
this->pref_ = global_preferences.make_preference<float>(this->get_object_id_hash());
|
||||
|
||||
float recovered;
|
||||
if (this->pref_.load(&recovered)) {
|
||||
this->publish_state_and_save(recovered);
|
||||
} else {
|
||||
this->publish_state_and_save(0);
|
||||
}
|
||||
this->last_update_ = millis();
|
||||
this->last_save_ = this->last_update_;
|
||||
|
||||
this->parent_->add_on_state_callback([this](float state) { this->process_new_state_(state); });
|
||||
}
|
||||
|
||||
void TotalDailyEnergy::dump_config() { LOG_SENSOR("", "Total Daily Energy", this); }
|
||||
|
||||
void TotalDailyEnergy::loop() {
|
||||
auto t = this->time_->now();
|
||||
if (!t.is_valid())
|
||||
return;
|
||||
|
||||
if (this->last_day_of_year_ == 0) {
|
||||
this->last_day_of_year_ = t.day_of_year;
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.day_of_year != this->last_day_of_year_) {
|
||||
this->last_day_of_year_ = t.day_of_year;
|
||||
this->total_energy_ = 0;
|
||||
this->publish_state_and_save(0);
|
||||
}
|
||||
}
|
||||
|
||||
void TotalDailyEnergy::publish_state_and_save(float state) {
|
||||
this->total_energy_ = state;
|
||||
this->publish_state(state);
|
||||
const uint32_t now = millis();
|
||||
if (now - this->last_save_ < this->min_save_interval_) {
|
||||
return;
|
||||
}
|
||||
this->last_save_ = now;
|
||||
this->pref_.save(&state);
|
||||
}
|
||||
|
||||
void TotalDailyEnergy::process_new_state_(float state) {
|
||||
if (isnan(state))
|
||||
return;
|
||||
const uint32_t now = millis();
|
||||
const float old_state = this->last_power_state_;
|
||||
const float new_state = state;
|
||||
float delta_hours = (now - this->last_update_) / 1000.0f / 60.0f / 60.0f;
|
||||
float delta_energy = 0.0f;
|
||||
switch (this->method_) {
|
||||
case TOTAL_DAILY_ENERGY_METHOD_TRAPEZOID:
|
||||
delta_energy = delta_hours * (old_state + new_state) / 2.0;
|
||||
break;
|
||||
case TOTAL_DAILY_ENERGY_METHOD_LEFT:
|
||||
delta_energy = delta_hours * old_state;
|
||||
break;
|
||||
case TOTAL_DAILY_ENERGY_METHOD_RIGHT:
|
||||
delta_energy = delta_hours * new_state;
|
||||
break;
|
||||
}
|
||||
this->last_power_state_ = new_state;
|
||||
this->last_update_ = now;
|
||||
this->publish_state_and_save(this->total_energy_ + delta_energy);
|
||||
}
|
||||
|
||||
} // namespace total_daily_energy
|
||||
} // namespace esphome
|
49
components/total_daily_energy/total_daily_energy.h
Normal file
49
components/total_daily_energy/total_daily_energy.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace total_daily_energy {
|
||||
|
||||
enum TotalDailyEnergyMethod {
|
||||
TOTAL_DAILY_ENERGY_METHOD_TRAPEZOID = 0,
|
||||
TOTAL_DAILY_ENERGY_METHOD_LEFT,
|
||||
TOTAL_DAILY_ENERGY_METHOD_RIGHT,
|
||||
};
|
||||
|
||||
class TotalDailyEnergy : public sensor::Sensor, public Component {
|
||||
public:
|
||||
void set_min_save_interval(uint32_t min_interval) { this->min_save_interval_ = min_interval; }
|
||||
void set_time(time::RealTimeClock *time) { time_ = time; }
|
||||
void set_parent(Sensor *parent) { parent_ = parent; }
|
||||
void set_method(TotalDailyEnergyMethod method) { method_ = method; }
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
std::string unit_of_measurement() override { return this->parent_->get_unit_of_measurement() + "h"; }
|
||||
std::string icon() override { return this->parent_->get_icon(); }
|
||||
int8_t accuracy_decimals() override { return this->parent_->get_accuracy_decimals() + 2; }
|
||||
void loop() override;
|
||||
|
||||
void publish_state_and_save(float state);
|
||||
|
||||
protected:
|
||||
void process_new_state_(float state);
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
time::RealTimeClock *time_;
|
||||
Sensor *parent_;
|
||||
TotalDailyEnergyMethod method_;
|
||||
uint16_t last_day_of_year_{};
|
||||
uint32_t last_update_{0};
|
||||
uint32_t last_save_{0};
|
||||
uint32_t min_save_interval_{0};
|
||||
float total_energy_{0.0f};
|
||||
float last_power_state_{0.0f};
|
||||
};
|
||||
|
||||
} // namespace total_daily_energy
|
||||
} // namespace esphome
|
@ -1,6 +1,9 @@
|
||||
# Tuya Light Plus Component
|
||||
# Tuya Dimmer as Fan Component
|
||||
## Overview
|
||||
This a modified version of the Tuya fan component I use with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) (but it will likely work with other Tuya dimmers) to control bathroom fans. The major change from the standard Tuya fan component (other than removing options for speed, oscillation, and direction) is adding a function to always change the dimmer back to the maximum "brightness" effectively making this only an on/off device. Similar to the Tuya Light Plus component this component can also add a power sensor based on configured wattage of the fan, this could be done with a templat sensor and automations but it was easy to add here so I figured why not.
|
||||
This a modified version of the [Tuya fan](https://esphome.io/components/fan/tuya.html) component I use with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) (but it will likely work with other Tuya dimmers) to control bathroom fans. Changes from the standard Tuya fan component include the following:
|
||||
* Remove options for speed, oscillation, and direction as they don't apply.
|
||||
* Always change the "brightness" back to the maximum value effectively making this only an on/off device.
|
||||
* Can add a sensor to report current power usage based on a configured wattage of the fan(s) it controls.
|
||||
|
||||
|
||||
## Setup
|
||||
@ -32,15 +35,14 @@ fan:
|
||||
power:
|
||||
id: my_fan_power
|
||||
name: My Fan Power
|
||||
light_wattage: 21.6
|
||||
fan_wattage: 21.6
|
||||
update_interval: 60s
|
||||
```
|
||||
|
||||
## Configuration Variables
|
||||
* id (Optional, ID): Manually specify the ID used for code generation.
|
||||
* name (Required, string): The name of the light.
|
||||
* switch_datapoint (Required, int): The datapoint id number of the power switch.
|
||||
## Configuration Variables (In addition to the standard variables)
|
||||
* dimmer_datapoint (Required, int): The datapoint id number of the dimmer value.
|
||||
* dimmer_max_value (Optional, int, default 255): The highest dimmer value allowed.
|
||||
* power.id (Optional, string) Manually specify the power sensor ID used for code generation.
|
||||
* power.name (Optional, string) The name for the power sensor.
|
||||
* power.fan_wattage (Optional, float) The total wattage of the fan(s) controled by this dimmer.
|
||||
* power.update_interval (Optional, Time, default: 60s) Amount of time between updates of the power value while on.
|
||||
|
@ -10,6 +10,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_POWER,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
ICON_POWER,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["tuya"]
|
||||
@ -38,6 +39,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_FAN_WATTAGE): cv.positive_float,
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.update_interval,
|
||||
}
|
||||
),
|
||||
}
|
||||
@ -63,3 +65,6 @@ async def to_code(config):
|
||||
power_sensor = await sensor.new_sensor(power_config)
|
||||
cg.add(var.set_fan_wattage(power_config[CONF_FAN_WATTAGE]))
|
||||
cg.add(var.set_power_sensor(power_sensor))
|
||||
cg.add(var.set_update_interval(power_config[CONF_UPDATE_INTERVAL]))
|
||||
else:
|
||||
cg.add(var.set_update_interval(4294967295)) # uint32_t max
|
||||
|
@ -42,5 +42,13 @@ void TuyaDimmerAsFan::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Dimmer has datapoint ID %u", *this->dimmer_id_);
|
||||
}
|
||||
|
||||
void TuyaDimmerAsFan::update()
|
||||
{
|
||||
if (this->fan_wattage_.has_value() && this->power_sensor_ != nullptr && this->fan_->state)
|
||||
{
|
||||
this->power_sensor_->publish_state(this->fan_wattage_.value());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tuya
|
||||
} // namespace esphome
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace esphome {
|
||||
namespace tuya {
|
||||
|
||||
class TuyaDimmerAsFan : public Component {
|
||||
class TuyaDimmerAsFan : public PollingComponent {
|
||||
public:
|
||||
TuyaDimmerAsFan(Tuya *parent, fan::FanState *fan) : parent_(parent), fan_(fan) {}
|
||||
void setup() override;
|
||||
@ -18,6 +18,7 @@ class TuyaDimmerAsFan : public Component {
|
||||
void set_dimmer_max_value(uint32_t max_value) { this->dimmer_max_value_ = max_value; }
|
||||
void set_fan_wattage(float fan_wattage) { this->fan_wattage_ = fan_wattage; }
|
||||
void set_power_sensor(sensor::Sensor *power_sensor) { this->power_sensor_ = power_sensor; }
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
Tuya *parent_;
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Tuya Light Plus Component
|
||||
## Overview
|
||||
This an enhanced version of the standard Tuya light component that adds a bunch of extra features. I use this component with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) but it will likely work with other Tuya dimmers. Extra features include the following:
|
||||
This an enhanced version of the standard [Tuya light](https://esphome.io/components/light/tuya.html) component that adds a bunch of extra features. I use this component with [Feit Dimmers](https://www.amazon.com/gp/product/B07SXDFH38/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1) but it will likely work with other Tuya dimmers. Extra features include the following:
|
||||
* Resets the brightness level back to a default level when turned off so that it always comes on at the same level instead of the level it was at when turned off.
|
||||
* The default level can be different during the "day" vs at "night" when everyone is in bed. Day and Night are based on a sensor (binary or text)in Home Assistant.
|
||||
* The default level can be updated via a service that is added to Home Assistant by this component.
|
||||
@ -11,7 +11,7 @@ This an enhanced version of the standard Tuya light component that adds a bunch
|
||||
* Double clicking the dimmer while off can be configured to leave the light in an off or on state.
|
||||
* Adds an option to configure action(s) to run when the dimmer is double clicked while on (this double click always turns the light off otherwise you get strange flash when double clicking).
|
||||
* Allows you to "link" other light(s) in Home Assistant that will be controlled by this dimmer (on/off and level).
|
||||
* Can add a sensor to report current power usage based on a configured wattage of the lights it controls. Currently this reports the specified wattage regardless of the dimmer level (my lights run at the max level 95% of the time so for me this is pretty accurate). Eventually I want to determine approximately what the dimmer level to power reduction ratio is so that it can more accurately report the power.
|
||||
* Can add a sensor to report current power usage based on a configured wattage of the light(s) it controls. Currently this reports the specified wattage regardless of the dimmer level (my lights run at the max level 95% of the time so for me this is pretty accurate). Eventually I want to determine approximately what the dimmer level to power reduction ratio is so that it can more accurately report the power.
|
||||
|
||||
|
||||
## Setup
|
||||
@ -60,17 +60,10 @@ light:
|
||||
id: my_light_power
|
||||
name: My Light Power
|
||||
light_wattage: 21.6
|
||||
|
||||
update_interval: 60s
|
||||
```
|
||||
|
||||
## Configuration Variables
|
||||
* id (Optional, ID): Manually specify the ID used for code generation.
|
||||
* name (Required, string): The name of the light.
|
||||
* switch_datapoint (Required, int): The datapoint id number of the power switch.
|
||||
* dimmer_datapoint (Required, int): The datapoint id number of the dimmer value.
|
||||
* min_value_datapoint (Optional, int): The datapoint id number of the MCU minimum value setting. If this is set then ESPHome will sync the min_value to the MCU on startup.
|
||||
* min_value (Optional, int, default 0): The lowest dimmer value allowed.
|
||||
* max_value (Optional, int, default 255): The highest dimmer value allowed.
|
||||
## Configuration Variables (In addition to the standard variables)
|
||||
* default_brightness (Optional, int 1-255): The default brightness level for the light.
|
||||
* auto_off_time (Optional, Time): The amount of time to wait before automatically turning the light off, 0 disables auto off
|
||||
* linked_lights (Optional, string): List of lights that will be controlled by this dimmer (note this one direction, changes to the linked light will not be applied to this light).
|
||||
@ -88,6 +81,7 @@ light:
|
||||
* power.id (Optional, string) Manually specify the power sensor ID used for code generation.
|
||||
* power.name (Optional, string) The name for the power sensor
|
||||
* power.light_wattage (Optional, float) The total wattage of the light(s) controled by this dimmer
|
||||
* power.update_interval (Optional, Time, default: 60s) Amount of time between updates of the power value while on.
|
||||
|
||||
## Operation
|
||||
This component adds 2 services to Home Assistant that can be used to update the settings of the dimmer:
|
||||
|
@ -17,6 +17,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_POWER,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
ICON_POWER,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
)
|
||||
from esphome.components.tuya import CONF_TUYA_ID, Tuya
|
||||
|
||||
@ -43,7 +44,7 @@ CONF_LIGHT_WATTAGE = "light_wattage"
|
||||
tuya_ns = cg.esphome_ns.namespace("tuya")
|
||||
api_ns = cg.esphome_ns.namespace("api")
|
||||
APIServer = api_ns.class_("APIServer", cg.Component, cg.Controller)
|
||||
TuyaLight = tuya_ns.class_("TuyaLightPlus", light.LightOutput, cg.Component, APIServer)
|
||||
TuyaLight = tuya_ns.class_("TuyaLightPlus", light.LightOutput, cg.PollingComponent, APIServer)
|
||||
DoubleClickWhileOffTrigger = tuya_ns.class_('DoubleClickWhileOffTrigger', auto.Trigger.template())
|
||||
DoubleClickWhileOnTrigger = tuya_ns.class_('DoubleClickWhileOnTrigger', auto.Trigger.template())
|
||||
|
||||
@ -104,6 +105,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_LIGHT_WATTAGE): cv.positive_float,
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.update_interval,
|
||||
}
|
||||
),
|
||||
}
|
||||
@ -166,5 +168,8 @@ async def to_code(config):
|
||||
power_sensor = await sensor.new_sensor(power_config)
|
||||
cg.add(var.set_light_wattage(power_config[CONF_LIGHT_WATTAGE]))
|
||||
cg.add(var.set_power_sensor(power_sensor))
|
||||
cg.add(var.set_update_interval(power_config[CONF_UPDATE_INTERVAL]))
|
||||
else:
|
||||
cg.add(var.set_update_interval(4294967295)) # uint32_t max
|
||||
paren = await cg.get_variable(config[CONF_TUYA_ID])
|
||||
cg.add(var.set_tuya_parent(paren))
|
||||
|
@ -89,6 +89,14 @@ void TuyaLightPlus::loop()
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::update()
|
||||
{
|
||||
if (this->light_wattage_.has_value() && this->power_sensor_ != nullptr && this->state_->current_values.is_on())
|
||||
{
|
||||
this->power_sensor_->publish_state(this->light_wattage_.value());
|
||||
}
|
||||
}
|
||||
|
||||
void TuyaLightPlus::add_new_double_click_while_off_callback(std::function<void()> &&callback)
|
||||
{
|
||||
this->has_double_click_while_off_ = true;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/tuya/tuya.h"
|
||||
#include "esphome/components/light/light_output.h"
|
||||
#include "esphome/components/api/custom_api_device.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace tuya {
|
||||
@ -13,7 +13,7 @@ enum DayNightSensorType {
|
||||
TEXT,
|
||||
};
|
||||
|
||||
class TuyaLightPlus : public Component, public light::LightOutput, public api::CustomAPIDevice {
|
||||
class TuyaLightPlus : public light::LightOutput, public PollingComponent, public api::CustomAPIDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
@ -29,6 +29,7 @@ class TuyaLightPlus : public Component, public light::LightOutput, public api::C
|
||||
void setup_state(light::LightState *state) override;
|
||||
void write_state(light::LightState *state) override;
|
||||
void loop() override;
|
||||
void update() override;
|
||||
|
||||
void set_linked_lights(const std::string linked_lights) { this->linked_lights_ = linked_lights; }
|
||||
void set_day_night_sensor(const std::string day_night_sensor) { this->day_night_sensor_ = day_night_sensor; }
|
||||
|
@ -12,6 +12,10 @@ packages:
|
||||
device_base: !include ../packages/device_base.yaml
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ binary_light_with_power, total_daily_energy ]
|
||||
- source: github://cbpowell/ESPSense
|
||||
components: [ espsense ]
|
||||
|
||||
@ -46,18 +50,14 @@ fan:
|
||||
name: "Basement Bathroom Fan"
|
||||
|
||||
light:
|
||||
- platform: binary
|
||||
- platform: binary_light_with_power
|
||||
id: the_light
|
||||
name: "Basement Bathroom Light"
|
||||
output: light_output
|
||||
on_turn_on:
|
||||
- sensor.template.publish:
|
||||
id: light_power
|
||||
state: 48.0
|
||||
on_turn_off:
|
||||
- sensor.template.publish:
|
||||
id: light_power
|
||||
state: 0.0
|
||||
power:
|
||||
id: light_power
|
||||
name: Basement Bathroom Light Power
|
||||
light_wattage: 48.0
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
@ -73,17 +73,11 @@ status_led:
|
||||
inverted: true
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
name: Basement Bathroom Light Power
|
||||
id: light_power
|
||||
unit_of_measurement: W
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
- platform: total_daily_energy
|
||||
name: Basement Bathroom Light
|
||||
power_id: light_power
|
||||
state_class: measurement
|
||||
method: left
|
||||
min_save_interval: 10min
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
|
@ -14,6 +14,10 @@ packages:
|
||||
external_components:
|
||||
- source: github://cbpowell/ESPSense
|
||||
components: [ espsense ]
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ binary_light_with_power, gpio_switch_with_power, total_daily_energy ]
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
@ -35,7 +39,7 @@ binary_sensor:
|
||||
|
||||
espsense:
|
||||
plugs:
|
||||
- name: Basement Bathroom Shower Light
|
||||
- name: Basement Shower Light
|
||||
power_sensor: light_power
|
||||
voltage: 120
|
||||
- name: Basement Bathroom Heater
|
||||
@ -43,18 +47,14 @@ espsense:
|
||||
voltage: 120
|
||||
|
||||
light:
|
||||
- platform: binary
|
||||
- platform: binary_light_with_power
|
||||
id: the_light
|
||||
name: "Basement Shower Light"
|
||||
name: Basement Shower Light
|
||||
output: light_output
|
||||
on_turn_on:
|
||||
- sensor.template.publish:
|
||||
id: light_power
|
||||
state: 11.5
|
||||
on_turn_off:
|
||||
- sensor.template.publish:
|
||||
id: light_power
|
||||
state: 0.0
|
||||
power:
|
||||
id: light_power
|
||||
name: Basement Shower Light Power
|
||||
light_wattage: 11.5
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
@ -67,43 +67,27 @@ status_led:
|
||||
inverted: true
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
- platform: gpio_switch_with_power
|
||||
id: heater
|
||||
name: "Basement Bathroom Heater"
|
||||
name: Basement Bathroom Heater
|
||||
icon: mdi:radiator
|
||||
pin: 4
|
||||
on_turn_on:
|
||||
- sensor.template.publish:
|
||||
id: heat_power
|
||||
state: 500
|
||||
on_turn_off:
|
||||
- sensor.template.publish:
|
||||
id: heat_power
|
||||
state: 0.0
|
||||
power:
|
||||
id: heat_power
|
||||
name: Basement Bathroom Heater Power
|
||||
device_wattage: 500.0
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
name: Basement Bathroom Shower Light
|
||||
id: light_power
|
||||
unit_of_measurement: W
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
- platform: template
|
||||
name: Basement Bathroom Heater
|
||||
id: heat_power
|
||||
unit_of_measurement: W
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
- platform: total_daily_energy
|
||||
name: Basement Bathroom Shower Light
|
||||
name: Basement Shower Light
|
||||
power_id: light_power
|
||||
state_class: measurement
|
||||
method: left
|
||||
min_save_interval: 10min
|
||||
- platform: total_daily_energy
|
||||
name: Basement Bathroom Heater
|
||||
power_id: heat_power
|
||||
state_class: measurement
|
||||
method: left
|
||||
min_save_interval: 10min
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
|
@ -22,11 +22,11 @@ light:
|
||||
sensor_type: text
|
||||
sensor_day_value: Day
|
||||
sensor_night_value: Night
|
||||
day_default_brightness: 255
|
||||
day_default_brightness: 128
|
||||
night_default_brightness: 1
|
||||
day_auto_off_time: 0 min
|
||||
night_auto_off_time: 15 min
|
||||
power:
|
||||
id: power
|
||||
name: ${device_name} Power
|
||||
light_wattage: 35.5
|
||||
light_wattage: 81.5
|
||||
|
@ -22,7 +22,7 @@ light:
|
||||
sensor_type: text
|
||||
sensor_day_value: Day
|
||||
sensor_night_value: Night
|
||||
day_default_brightness: 255
|
||||
day_default_brightness: 128
|
||||
night_default_brightness: 1
|
||||
day_auto_off_time: 0 min
|
||||
night_auto_off_time: 15 min
|
||||
|
@ -12,27 +12,27 @@ packages:
|
||||
device_base: !include ../packages/device_base.yaml
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ binary_light_with_power, total_daily_energy ]
|
||||
- source: github://cbpowell/ESPSense
|
||||
components: [ espsense ]
|
||||
|
||||
espsense:
|
||||
plugs:
|
||||
- name: Patio Lights
|
||||
- name: ${device_name}
|
||||
power_sensor: power
|
||||
voltage: 120
|
||||
|
||||
light:
|
||||
- platform: binary
|
||||
name: "Patio Lights"
|
||||
- platform: binary_light_with_power
|
||||
name: ${device_name}
|
||||
output: patio_lights_output
|
||||
on_turn_on:
|
||||
- sensor.template.publish:
|
||||
id: power
|
||||
state: 15.3
|
||||
on_turn_off:
|
||||
- sensor.template.publish:
|
||||
id: power
|
||||
state: 0.0
|
||||
power:
|
||||
id: power
|
||||
name: ${device_name} Power
|
||||
light_wattage: 15.3
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
@ -40,17 +40,11 @@ output:
|
||||
pin: D1
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
name: Patio Lights Power
|
||||
id: power
|
||||
unit_of_measurement: W
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
- platform: total_daily_energy
|
||||
name: Patio Lights
|
||||
name: ${device_name}
|
||||
power_id: power
|
||||
state_class: measurement
|
||||
method: left
|
||||
min_save_interval: 10min
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
|
@ -16,6 +16,10 @@ esphome:
|
||||
- ../custom/TreoLedPoolLight.h
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ binary_light_with_power, total_daily_energy ]
|
||||
- source: github://cbpowell/ESPSense
|
||||
components: [ espsense ]
|
||||
|
||||
@ -93,7 +97,8 @@ sensor:
|
||||
- platform: total_daily_energy
|
||||
name: Pool Lights
|
||||
power_id: pool_light_power
|
||||
state_class: measurement
|
||||
method: left
|
||||
min_save_interval: 10min
|
||||
|
||||
status_led:
|
||||
pin:
|
||||
|
@ -177,7 +177,7 @@ time:
|
||||
int hour = now.hour;
|
||||
int minute = now.minute;
|
||||
|
||||
if (hour == 4 && minute == 45)
|
||||
if (hour == 3 && minute == 45)
|
||||
{
|
||||
auto ha_service = new api::HomeAssistantServiceCallAction<>(api_apiserver, false);
|
||||
ha_service->set_service("switch.turn_off");
|
||||
@ -186,7 +186,7 @@ time:
|
||||
id(pool_cleaner).turn_off();
|
||||
id(pool_pump).turn_on();
|
||||
}
|
||||
else if (hour >= 5 && hour <= 6)
|
||||
else if (hour >= 4 && hour <= 5)
|
||||
{
|
||||
auto ha_service = new api::HomeAssistantServiceCallAction<>(api_apiserver, false);
|
||||
ha_service->set_service("switch.turn_off");
|
||||
@ -201,7 +201,7 @@ time:
|
||||
id(pool_pump).turn_on();
|
||||
}
|
||||
}
|
||||
else if (hour == 7)
|
||||
else if (hour == 6)
|
||||
{
|
||||
auto ha_service = new api::HomeAssistantServiceCallAction<>(api_apiserver, false);
|
||||
ha_service->set_service("switch.turn_on");
|
||||
@ -210,11 +210,11 @@ time:
|
||||
id(pool_cleaner).turn_off();
|
||||
id(pool_pump).turn_on();
|
||||
}
|
||||
else if (hour >= 8 && hour <= 21 && (minute == 0 || minute == 30))
|
||||
else if (hour >= 7 && hour <= 20 && (minute == 0 || minute == 30))
|
||||
{
|
||||
id(pool_pump).turn_off();
|
||||
}
|
||||
else if (hour >= 8 && hour <= 21 && (minute == 15 || minute == 45))
|
||||
else if (hour >= 8 && hour <= 20 && (minute == 15 || minute == 45))
|
||||
{
|
||||
auto ha_service = new api::HomeAssistantServiceCallAction<>(api_apiserver, false);
|
||||
ha_service->set_service("switch.turn_on");
|
||||
@ -223,7 +223,7 @@ time:
|
||||
id(pool_cleaner).turn_off();
|
||||
id(pool_pump).turn_on();
|
||||
}
|
||||
else if (hour == 22 && minute == 0)
|
||||
else if (hour == 21 && minute == 0)
|
||||
{
|
||||
auto ha_service = new api::HomeAssistantServiceCallAction<>(api_apiserver, false);
|
||||
ha_service->set_service("switch.turn_off");
|
||||
|
@ -6,7 +6,7 @@ external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ tuya, tuya_light_plus ]
|
||||
components: [ tuya, tuya_light_plus, total_daily_energy ]
|
||||
- source: github://cbpowell/ESPSense
|
||||
components: [ espsense ]
|
||||
|
||||
@ -25,7 +25,8 @@ sensor:
|
||||
- platform: total_daily_energy
|
||||
name: ${device_name}
|
||||
power_id: power
|
||||
state_class: measurement
|
||||
method: left
|
||||
min_save_interval: 10min
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
|
@ -6,7 +6,7 @@ external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
components: [ tuya, tuya_dimmer_as_fan ]
|
||||
components: [ tuya, tuya_dimmer_as_fan, total_daily_energy ]
|
||||
- source: github://cbpowell/ESPSense
|
||||
components: [ espsense ]
|
||||
|
||||
@ -37,7 +37,8 @@ sensor:
|
||||
- platform: total_daily_energy
|
||||
name: ${device_name}
|
||||
power_id: power
|
||||
state_class: measurement
|
||||
method: left
|
||||
min_save_interval: 10min
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
|
Loading…
x
Reference in New Issue
Block a user