From dde2a2cc33de1b1e01935a2a528d51df01e0f812 Mon Sep 17 00:00:00 2001 From: manuel Date: Wed, 26 Nov 2025 10:56:48 +0100 Subject: Add fan control to couchlight --- esphome/config/couchlight.yaml | 234 +++++++++++++++++----- esphome/config/my_components/mycc1101/__init__.py | 22 ++ esphome/config/my_components/mycc1101/mycc1101.h | 39 ++++ 3 files changed, 245 insertions(+), 50 deletions(-) create mode 100644 esphome/config/my_components/mycc1101/__init__.py create mode 100644 esphome/config/my_components/mycc1101/mycc1101.h diff --git a/esphome/config/couchlight.yaml b/esphome/config/couchlight.yaml index ad6da9d..7244163 100644 --- a/esphome/config/couchlight.yaml +++ b/esphome/config/couchlight.yaml @@ -1,10 +1,22 @@ substitutions: device_name: couchlight friendly_name: "Couch Light" + fan_code: "0000" + +external_components: + - source: github://pr#6300 + components: [ cc1101 ] + - source: my_components + components: [ mycc1101 ] esphome: name: ${device_name} friendly_name: ${friendly_name} + devices: + - id: couchlight + name: "Couch Light" + - id: fancontrol + name: "Fan Control" on_boot: then: - lock.template.publish: @@ -43,77 +55,46 @@ wifi: captive_portal: light: - - platform: binary - id: light1 + - id: light1 + device_id: couchlight + platform: binary name: "Spot 1" output: relay_light1 - - platform: binary - id: light2 + - id: light2 + device_id: couchlight + platform: binary name: "Spot 2" output: relay_light2 output: - - platform: gpio - id: relay_light1 + - id: relay_light1 + platform: gpio pin: GPIO5 # D1 - - platform: gpio - id: relay_light2 + - id: relay_light2 + platform: gpio pin: GPIO4 # D2 # UNUSED GPIO - - platform: gpio - id: unused_gpio0 - pin: - number: GPIO0 # D3 - mode: INPUT_PULLUP - platform: gpio id: unused_gpio1 pin: number: TX # GPIO1 mode: INPUT_PULLUP - - platform: gpio - id: unused_gpio2 - pin: - number: GPIO2 # D4 - mode: INPUT_PULLUP - platform: gpio id: unused_gpio3 pin: number: RX # GPIO3 mode: INPUT_PULLUP - - platform: gpio - id: unused_gpio14 - pin: - number: GPIO14 # D5 - mode: INPUT_PULLUP - - platform: gpio - id: unused_gpio15 - pin: - number: GPIO15 # D8 - mode: INPUT_PULLUP - - platform: gpio - id: unused_gpio16 - pin: - number: GPIO16 # D0 - mode: INPUT_PULLDOWN - -script: - - id: reset_child_lock - mode: restart - then: - - delay: 30min - - lock.template.publish: - id: child_lock - state: UNLOCKED binary_sensor: - - platform: gpio - id: button_light1 + - id: button_light1 + device_id: couchlight + platform: gpio name: "Spot 1 PushButton" pin: - number: GPIO13 # D7 + number: GPIO2 # D4 mode: INPUT_PULLUP filters: - invert @@ -127,11 +108,12 @@ binary_sensor: - light.toggle: light1 internal: true # hide from UI - - platform: gpio - id: button_light2 + - id: button_light2 + device_id: couchlight + platform: gpio name: "Spot 2 PushButton" pin: - number: GPIO12 # D6 + number: GPIO0 # D3 mode: INPUT_PULLUP filters: - invert @@ -146,8 +128,9 @@ binary_sensor: internal: true # hide from UI lock: - - platform: template - id: child_lock + - id: child_lock + device_id: couchlight + platform: template name: "Child Lock" optimistic: true on_lock: @@ -155,3 +138,154 @@ lock: on_unlock: - script.stop: reset_child_lock +spi: + clk_pin: GPIO14 # D5 + miso_pin: GPIO12 # D6 + mosi_pin: GPIO13 # D7 + +mycc1101: + id: transceiver + cs_pin: GPIO15 # D8 + gdo0_pin: + number: GPIO16 # D0 + allow_other_uses: true + output_power: 10 # 5 + tuner: + frequency: 433920 + if_frequency: 153 + bandwidth: 270 + symbol_rate: 6000 + sync_mode: None + carrier_sense_above_threshold: false + modulation: ASK/OOK + +remote_transmitter: + pin: + number: GPIO16 # same as GDO0 + allow_other_uses: true + carrier_duty_percent: 100% + +fan: + - id: myfan + device_id: fancontrol + platform: template + name: "Fan" + speed_count: 6 + has_direction: true + restore_mode: ALWAYS_OFF + on_turn_off: + - logger.log: "on_turn_off" + - lambda: |- + id(transceiver)->wakeup(); + id(fan_stop_frames).execute(); + id(transceiver)->power_down(); + on_turn_on: + - logger.log: "on_turn_on" + - lambda: |- + id(transceiver)->wakeup(); + auto x = id(myfan).speed; + if (x == 1) { id(fan_speed1_frames).execute(); } + else if (x == 2) { id(fan_speed2_frames).execute(); } + else if (x == 3) { id(fan_speed3_frames).execute(); } + else if (x == 4) { id(fan_speed4_frames).execute(); } + else if (x == 5) { id(fan_speed5_frames).execute(); } + else if (x == 6) { id(fan_speed6_frames).execute(); } + id(transceiver)->power_down(); + on_speed_set: + - logger.log: "on_speed_set" + - lambda: |- + if (!id(myfan).state) + return; + id(transceiver)->wakeup(); + if (x == 1) { id(fan_speed1_frames).execute(); } + else if (x == 2) { id(fan_speed2_frames).execute(); } + else if (x == 3) { id(fan_speed3_frames).execute(); } + else if (x == 4) { id(fan_speed4_frames).execute(); } + else if (x == 5) { id(fan_speed5_frames).execute(); } + else if (x == 6) { id(fan_speed6_frames).execute(); } + id(transceiver)->power_down(); + on_direction_set: + - logger.log: "on_direction_set" + - lambda: |- + if (!id(myfan).state) + return; + id(transceiver)->wakeup(); + id(fan_reverse_frames).execute(); + id(transceiver)->power_down(); + +script: + - id: reset_child_lock + mode: restart + then: + - delay: 30min + - lock.template.publish: + id: child_lock + state: UNLOCKED + + # see https://www.alldatasheet.com/datasheet-pdf/pdf/114193/ETC1/M1EN.html + # code format is 0 0 + # commands: + # - stop: 111101 + # - lvl1: 110111 + # - lvl2: 110101 + # - lvl3: 101111 + # - lvl4: 100111 + # - lvl5: 011101 + # - lvl6: 011111 + # - light: 111110 + # - reverse: 111011 + - id: fan_stop_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0111101" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_speed1_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0110111" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_speed2_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0110101" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_speed3_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0101111" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_speed4_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0100111" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_speed5_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0011101" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_speed6_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0011111" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_toggle_light_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0111110" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + - id: fan_reverse_frames + then: + - remote_transmitter.transmit_rc_switch_raw_cc1101: + code: "0${fan_code}0111011" + protocol: { pulse_length: 250, sync: [35,1], zero: [1,2], one: [2,1], inverted: true } + repeat: { times: 10, wait_time: 0s } + diff --git a/esphome/config/my_components/mycc1101/__init__.py b/esphome/config/my_components/mycc1101/__init__.py new file mode 100644 index 0000000..14261fb --- /dev/null +++ b/esphome/config/my_components/mycc1101/__init__.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +from esphome.components import spi, remote_base +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_PROTOCOL, CONF_CODE +from esphome.components import cc1101 +from types import FunctionType + +cc1101.MULTI_CONF_NO_DEFAULT = True +AUTO_LOAD = ["cc1101"] +DEPENDENCIES = cc1101.DEPENDENCIES + +ns = cg.esphome_ns.namespace("cc1101") +MyCC1101Component = ns.class_("MyCC1101Component", cc1101.CC1101Component)#, cg.Component, spi.SPIDevice) + +CONFIG_SCHEMA = cc1101.CONFIG_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(MyCC1101Component), + } +) + +to_code = cc1101.to_code + diff --git a/esphome/config/my_components/mycc1101/mycc1101.h b/esphome/config/my_components/mycc1101/mycc1101.h new file mode 100644 index 0000000..95f714d --- /dev/null +++ b/esphome/config/my_components/mycc1101/mycc1101.h @@ -0,0 +1,39 @@ +#pragma once + +#include "esphome/components/cc1101/cc1101.h" +#include "esphome/components/cc1101/cc1101defs.h" + +namespace esphome { +namespace cc1101 { + +static const char *const TAG = "mycc1101"; + +class MyCC1101Component : public CC1101Component { + public: + void idle() { + ESP_LOGD(TAG, "idle"); + this->send_(Command::IDLE); + } + + void power_down() { + ESP_LOGD(TAG, "power_down"); + this->send_(Command::IDLE); + this->send_(Command::PWD); + } + + void wakeup() { + ESP_LOGD(TAG, "wakeup"); + this->cs_->digital_write(false); + delayMicroseconds(10); + this->cs_->digital_write(true); + delayMicroseconds(200); + + this->send_(Command::IDLE); + + // set patable after after wakeup + this->set_output_power(this->output_power_requested_); + } +}; + +} // namespace cc1101 +} // namespace esphome -- cgit v1.2.3