Add washing machine
This commit is contained in:
parent
28c41482c5
commit
655beac2f7
6 changed files with 350 additions and 3 deletions
|
|
@ -9,7 +9,7 @@ dkim-keys:
|
|||
radicale-htpasswd: ENC[AES256_GCM,data:Q0WnleP9I4xozsL/H+5oV3Ag7khfalV40A6ub+DA07U8UKna3/ju533RmjWOnETzSNa6XK140nfCcfGZCiqGyF9tfuuXcKFu+j4=,iv:87PSvHyKF7QUQZmEuxM+IT0VKSGnS0MjoUmCqJ+6tzI=,tag:yrP3TgxE8aSZf0MrCF9dsQ==,type:str]
|
||||
synapse-turn-shared-secret: ENC[AES256_GCM,data:Q1XRds3Zud1kYkvD6s9WUzP+kNDNsxB5SHd6oCAaLCHhHhYENSAYTZOF+rGjCPNyKFL0e/A=,iv:zScRQrz+pXHNUh/BGOaV+TVnDR3wu1Z/UO1zXarKwtA=,tag:ckpVziE+yb0FjctcT7tAkg==,type:str]
|
||||
rmfakecloud: ENC[AES256_GCM,data:ktKBKb6cRv1VF8tRvXIpxIy9hPinVPKK05mgvYzz18PEdcrCLpldm5xf7ffHtY5XzDOAMXDCiz6x4xyv7071frrF0spOEPnIzVhxwG8H2Ck=,iv:qJdHjv0RziAs4G9UGeRwGQ4GE5kaObJWpIYWpRKhr9c=,tag:PXgvU1hZK/gvWGyFJaHekg==,type:str]
|
||||
esphome: ENC[AES256_GCM,data:RykNTaLwXD9pvCepexxPv0TY5Hk1c1JQWerehuaTSfYIPJ8/tXWQ8XJWoHs7+wJZCV+7nXY9ZpWDlWdWUqDfKcHnv62BdwnuW5L9baY1PLq4WISpRKsND99euDLuicvbpej5GBwMhxr7XFKVkAlbEpAEj1c+qAv27gEg0tC4Jkn8nl4+qi+f9TeRXv1miijAFgxqZ+C+9nQ2NM6zeMXgD5NS0PqzgP43NhTrC8s0QYOb9Gry78jEbzEfvquFJ+CmqEwoL3NZ/ynQQlO3IUfOwmJlMyhEVmetPs8sMyMIbmHrLlfCKb9KFUjZCJAsJhSq2QgByPB6mHotd4Nu9P/1xkzuy+hQImrlIK7Sz4bo1tp9CM5czRwU6GOmG7haC2UebSSGzhp8cHnhDtMbKbyqDLdTBsn9ilI/lvzNbuvyvygcaos5a8o3nO9MtVrgvUKowIb5wOHxvUrr8fXIAyrLEAdMVNl0UtPlJSBCRe8WFulhqGrgGECzt/seBoRZvzsgwXnSZgbYGTjIA7UR//0J4p877HFQTdEiUVEudK9vp3u8/GoDKThIy3A=,iv:mVL86y99wQ2M8kum2IotrYQbqswcTgcglCQSegoYzFI=,tag:ZhW1eCd6B59eNhipTb/2Mg==,type:str]
|
||||
esphome: ENC[AES256_GCM,data:8mXqZnGaiWTO3pNozXCG/NmPEb9fTWBIs/2gX4xLPQwoUg8rw18pVfm0GbEQG1e/crV8ykeYcbKvvZdvVIrc4M/khoO7iuqJHURTcoQh/q/9pH1K2Tg+f7w6V24BozP3GnHXGo+zfo4gX8TgQzx7kktMIiWWnP5gyc1KOw5mQlGmOwfe/Ny6ziCWuGOCPIzd4qtMGOn2lie9HztJ5h0HR9NMJar007grRUS/DXtgw4Z6/PQ80bQJPJF3qsCuJuW9YiI1ImqherYiGaS+ptdZI/nkj9RZFrDBf1NOt1ZizROoeKKO0uJ134Rh+YeuAtWeT+NcQMnj20YdJ75aBHGd+Kx/fICOmO/yXKyuwk1ZyvIvnlauG0bgi2nMrAQJdgO7FRBflmZd6IIFv6a2kOHkS8sigBi2Movq/mZTEF13XBsFxgEZugEqh5MvEd10iaLusYNCa5pc3z5DoeAcbsOGfmcgy4RdHurtVImfLSvPyelRAsWXceOPzU+zLVyAGZ4MeqP5cO2oK1qC9sntMz3s5sjl7BsT9SieiaScK4Tdadh0ZjlzVYzh+XIDTvbgUu6EFmU3t4UeAanPywJIdnnJVMCvgN6FLHk098h9PL2DgKWfS8aiywKXctXUA78WYpYInqS531liF8Jc5HM91Azp1q+ImpzmZjfm0kgD7wLiGzZaPeKsQaB7ykMpvWpTSq+QHW4=,iv:qLn56QxmWFaYtz3MwZyCP7NEfypmWRW4HxQiZmn27fE=,tag:9bHVx5NDf3nZG0alxb4p1w==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
|
|
@ -25,8 +25,8 @@ sops:
|
|||
TjdZRldhSzVtMkVoTzY1NjdGbCswRVUK0pi+8UuLqRmytcR2ikxOAM02iccl8P1y
|
||||
ixv0PKPLd+vQ23QeeQy/TfoGx16XttaDUnUrPLZR3TUKtAcld8+m6w==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2023-12-13T21:51:59Z"
|
||||
mac: ENC[AES256_GCM,data:EIJ8A537IFnubCKL1QCZbhnsPG1qCDt2jGiYCaOolTvxzuB30xxSpqaUE++9wZopQbKn8MAayaO06zaj4D0ix+CrYokPqpI73/XC+rO33YZMQzb72fbRoy9oPQdb3LSlqNyNP7Gu7/Q/ByfEacLlg+wD+e6mmueHmnmF7wt1lZ8=,iv:vhF/KmogG7jJgl1jflvdlRwuA569xL0DEjjozXrqQRI=,tag:NyYvcbqFWwq89IJ0NeF3oA==,type:str]
|
||||
lastmodified: "2023-12-18T16:45:32Z"
|
||||
mac: ENC[AES256_GCM,data:ZsC4C+VpUnHuMyqHa3/TIursyWDPV1+we/cBrUhyeqeNdeDveJ4a26jmIzNxWWHbJU7uMPy6BF6iHpS91YK4m+KKSqoXZiTjB8b9p3y9ietT9XQOLXdt8pxVFBEOSH7g9DeVbrJUHTOhzYpugMqC/QXcDLE1GQwa0eGUq3JIDh8=,iv:vbDpVJAXvYw1qQ5Or6CxOs8OO4yhtlVF4zh07bkkFJw=,tag:IqVAItuv23AbbGQsPh5dsg==,type:str]
|
||||
pgp:
|
||||
- created_at: "2023-05-02T19:30:42Z"
|
||||
enc: |
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
CODEOWNERS = ["@jalr"]
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
#include "miele_w433.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <string>
|
||||
|
||||
namespace esphome {
|
||||
namespace miele_w433 {
|
||||
|
||||
static const char *const TAG = "miele_w433";
|
||||
|
||||
static const std::string OPERATION_STATES[] = {"inaktiv", "Einw./Vorwäsche", "Waschen", "Spülen", "Spülstop", "Pumpen", "Endschleudern", "Knitterschutz/Ende"};
|
||||
|
||||
void MieleW433Sensor::setup() {
|
||||
this->pin_clock_->setup();
|
||||
this->store_.pin_clock = this->pin_clock_->to_isr();
|
||||
this->pin_clock_->attach_interrupt(MieleW433SensorStore::gpio_intr_clock, &this->store_, gpio::INTERRUPT_RISING_EDGE);
|
||||
|
||||
this->pin_data_->setup();
|
||||
this->store_.pin_data = this->pin_data_;
|
||||
|
||||
if (this->pin_en_lamps_ != nullptr) {
|
||||
this->pin_en_lamps_->setup();
|
||||
this->store_.pin_en_lamps = this->pin_en_lamps_->to_isr();
|
||||
this->pin_en_lamps_->attach_interrupt(MieleW433SensorStore::gpio_intr_en_lamps, &this->store_, gpio::INTERRUPT_RISING_EDGE);
|
||||
}
|
||||
if (this->pin_en_7seg_ != nullptr) {
|
||||
this->pin_en_7seg_->setup();
|
||||
this->store_.pin_en_7seg = this->pin_en_7seg_->to_isr();
|
||||
this->pin_en_7seg_->attach_interrupt(MieleW433SensorStore::gpio_intr_en_7seg, &this->store_, gpio::INTERRUPT_RISING_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
void MieleW433Sensor::loop() {
|
||||
if (millis() - this->last_update_ > 1000) {
|
||||
uint32_t dpy_7seg;
|
||||
uint32_t dpy_lamps;
|
||||
{
|
||||
InterruptLock lock;
|
||||
dpy_7seg = this->store_.dpy_7seg;
|
||||
dpy_lamps = this->store_.dpy_lamps;
|
||||
}
|
||||
uint8_t minutes = (dpy_7seg & 0xf) * 60;
|
||||
minutes += ((dpy_7seg>>8) &0xf);
|
||||
minutes += ((dpy_7seg>>4) & 0xf) * 10;
|
||||
if (this->time_remaining_sensor_ != nullptr) {
|
||||
this->time_remaining_sensor_->publish_state(minutes);
|
||||
}
|
||||
|
||||
uint8_t state = 0;
|
||||
bool is_active = false;
|
||||
|
||||
switch(dpy_lamps & 0x1f007) {
|
||||
case 1<<0:
|
||||
// Pumpen
|
||||
state = 5;
|
||||
is_active = true;
|
||||
break;
|
||||
case 1<<1:
|
||||
// Endschleudern
|
||||
state = 6;
|
||||
is_active = true;
|
||||
break;
|
||||
case 1<<2:
|
||||
// Knitterschutz/Ende
|
||||
state = 7;
|
||||
break;
|
||||
case 1<<12:
|
||||
// Einw./Vorwäsche
|
||||
state = 1;
|
||||
is_active = true;
|
||||
break;
|
||||
case 1<<13:
|
||||
// Waschen
|
||||
state = 2;
|
||||
is_active = true;
|
||||
break;
|
||||
case 1<<14:
|
||||
// Spülen
|
||||
state = 3;
|
||||
is_active = true;
|
||||
break;
|
||||
case 1<<15:
|
||||
// Spülstop
|
||||
state = 4;
|
||||
is_active = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->current_operation_sensor_ != nullptr) {
|
||||
this->current_operation_sensor_->publish_state(OPERATION_STATES[state]);
|
||||
}
|
||||
|
||||
if (this->active_sensor_ != nullptr) {
|
||||
this->active_sensor_->publish_state(is_active);
|
||||
}
|
||||
|
||||
this->last_update_ = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void MieleW433Sensor::dump_config() {
|
||||
LOG_SENSOR("", "Miele W433", this);
|
||||
LOG_PIN(" Pin Clock: ", this->pin_clock_);
|
||||
LOG_PIN(" Pin Data: ", this->pin_data_);
|
||||
LOG_PIN(" Pin Enable 7-Segment: ", this->pin_en_7seg_);
|
||||
LOG_PIN(" Pin Enable Lamps: ", this->pin_en_lamps_);
|
||||
};
|
||||
|
||||
void IRAM_ATTR HOT MieleW433SensorStore::gpio_intr_clock(MieleW433SensorStore *arg) {
|
||||
if (!arg->pin_en_7seg.digital_read()) {
|
||||
if (arg->count_cycles_7seg <= 31) {
|
||||
if (arg->pin_data->digital_read()) {
|
||||
arg->tmp_7seg |= (1<<(31-arg->count_cycles_7seg));
|
||||
}
|
||||
else {
|
||||
arg->tmp_7seg &= ~(1<<(31-arg->count_cycles_7seg));
|
||||
}
|
||||
arg->count_cycles_7seg++;
|
||||
}
|
||||
}
|
||||
if (!arg->pin_en_lamps.digital_read()) {
|
||||
if (arg->count_cycles_lamps <= 31) {
|
||||
if (arg->pin_data->digital_read()) {
|
||||
arg->tmp_lamps |= (1<<(31-arg->count_cycles_lamps));
|
||||
}
|
||||
else {
|
||||
arg->tmp_lamps &= ~(1<<(31-arg->count_cycles_lamps));
|
||||
}
|
||||
arg->count_cycles_lamps++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR HOT MieleW433SensorStore::gpio_intr_en_lamps(MieleW433SensorStore *arg) {
|
||||
if (arg->count_cycles_lamps == 8) {
|
||||
arg->ctrl_lamps = arg->tmp_lamps>>24;
|
||||
}
|
||||
else if (arg->count_cycles_lamps == 24) {
|
||||
arg->dpy_lamps = arg->tmp_lamps>>8;
|
||||
}
|
||||
|
||||
arg->count_cycles_lamps = 0;
|
||||
}
|
||||
|
||||
void IRAM_ATTR HOT MieleW433SensorStore::gpio_intr_en_7seg(MieleW433SensorStore *arg) {
|
||||
if (arg->count_cycles_7seg == 8) {
|
||||
arg->ctrl_7seg = arg->tmp_7seg>>24;
|
||||
}
|
||||
else if (arg->count_cycles_7seg == 24) {
|
||||
arg->dpy_7seg = arg->tmp_7seg>>8;
|
||||
}
|
||||
arg->count_cycles_7seg = 0;
|
||||
}
|
||||
|
||||
} // namespace miele_w433
|
||||
} // namespace esphome
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace miele_w433 {
|
||||
|
||||
struct MieleW433SensorStore {
|
||||
ISRInternalGPIOPin pin_clock;
|
||||
InternalGPIOPin *pin_data;
|
||||
ISRInternalGPIOPin pin_en_7seg;
|
||||
ISRInternalGPIOPin pin_en_lamps;
|
||||
|
||||
static void gpio_intr_clock(MieleW433SensorStore *arg);
|
||||
static void gpio_intr_en_7seg(MieleW433SensorStore *arg);
|
||||
static void gpio_intr_en_lamps(MieleW433SensorStore *arg);
|
||||
|
||||
volatile int count_cycles_lamps = 0;
|
||||
volatile int count_cycles_7seg = 0;
|
||||
volatile uint32_t tmp_lamps;
|
||||
volatile uint32_t tmp_7seg;
|
||||
volatile uint32_t dpy_lamps;
|
||||
volatile uint8_t ctrl_lamps;
|
||||
volatile uint32_t dpy_7seg;
|
||||
volatile uint8_t ctrl_7seg;
|
||||
};
|
||||
|
||||
class MieleW433Sensor : public sensor::Sensor, public Component {
|
||||
public:
|
||||
void set_pin_clock(InternalGPIOPin *pin_clock) { pin_clock_ = pin_clock; }
|
||||
void set_pin_data(InternalGPIOPin *pin_data) { pin_data_ = pin_data; }
|
||||
void set_pin_en_7seg(InternalGPIOPin *pin_en_7seg) { pin_en_7seg_ = pin_en_7seg; }
|
||||
void set_pin_en_lamps(InternalGPIOPin *pin_en_lamps) { pin_en_lamps_ = pin_en_lamps; }
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
|
||||
void set_time_remaining_sensor(sensor::Sensor *sensor) { this->time_remaining_sensor_ = sensor; }
|
||||
void set_active_sensor(binary_sensor::BinarySensor *sensor) { this->active_sensor_ = sensor; }
|
||||
void set_current_operation_sensor(text_sensor::TextSensor *sensor) { this->current_operation_sensor_ = sensor; }
|
||||
|
||||
protected:
|
||||
InternalGPIOPin *pin_clock_;
|
||||
InternalGPIOPin *pin_data_;
|
||||
InternalGPIOPin *pin_en_7seg_{nullptr};
|
||||
InternalGPIOPin *pin_en_lamps_{nullptr};
|
||||
MieleW433SensorStore store_{};
|
||||
uint32_t last_update_ = 0;
|
||||
sensor::Sensor *time_remaining_sensor_{nullptr};
|
||||
binary_sensor::BinarySensor *active_sensor_{nullptr};
|
||||
text_sensor::TextSensor *current_operation_sensor_{nullptr};
|
||||
|
||||
//enum ErrorCode { NONE = 0, COMMUNICATION_FAILED, CRC_CHECK_FAILED } error_code_{NONE};
|
||||
};
|
||||
|
||||
} // namespace miele_w433
|
||||
} // namespace esphome
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import binary_sensor, sensor, text_sensor
|
||||
from esphome.const import (
|
||||
CONF_ACTIVE,
|
||||
CONF_BEEPER,
|
||||
CONF_CLOCK_PIN,
|
||||
CONF_CURRENT_OPERATION,
|
||||
CONF_DATA_PIN,
|
||||
CONF_DURATION,
|
||||
CONF_ID,
|
||||
CONF_STATUS,
|
||||
DEVICE_CLASS_LOCK,
|
||||
DEVICE_CLASS_PROBLEM,
|
||||
DEVICE_CLASS_RUNNING,
|
||||
DEVICE_CLASS_SWITCH,
|
||||
ICON_ROTATE_RIGHT,
|
||||
ICON_TIMELAPSE,
|
||||
UNIT_MINUTE,
|
||||
)
|
||||
|
||||
CONF_EN_7SEG_PIN = "enable_7segment_pin"
|
||||
CONF_EN_LAMPS_PIN = "enable_lamps_pin"
|
||||
CONF_TIME_REMAINING = "time_remaining"
|
||||
CONF_WATER_INLET = "water_inlet"
|
||||
CONF_WATER_OUTLET = "water_outlet"
|
||||
ICON_PLAY = "mdi:play"
|
||||
ICON_PLAYLIST_PLAY = "mdi:playlist-play"
|
||||
ICON_WATER_OFF = "mdi:water-off"
|
||||
|
||||
AUTO_LOAD = ["text_sensor", "binary_sensor"]
|
||||
DEPENDENCIES = []
|
||||
|
||||
miele_w433_ns = cg.esphome_ns.namespace("miele_w433")
|
||||
MieleW433Sensor = miele_w433_ns.class_("MieleW433Sensor", sensor.Sensor, cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(MieleW433Sensor),
|
||||
cv.Required(CONF_CLOCK_PIN): cv.All(pins.internal_gpio_input_pin_schema),
|
||||
cv.Required(CONF_DATA_PIN): cv.All(pins.internal_gpio_input_pin_schema),
|
||||
cv.Optional(CONF_EN_7SEG_PIN): pins.internal_gpio_input_pin_schema,
|
||||
cv.Optional(CONF_EN_LAMPS_PIN): pins.internal_gpio_input_pin_schema,
|
||||
cv.Optional(CONF_TIME_REMAINING): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_MINUTE,
|
||||
icon=ICON_TIMELAPSE,
|
||||
accuracy_decimals=0,
|
||||
),
|
||||
cv.Optional(CONF_ACTIVE): binary_sensor.binary_sensor_schema(
|
||||
device_class=DEVICE_CLASS_RUNNING, icon=ICON_PLAY
|
||||
),
|
||||
cv.Optional(CONF_CURRENT_OPERATION): text_sensor.text_sensor_schema(
|
||||
icon=ICON_PLAYLIST_PLAY
|
||||
),
|
||||
# cv.Optional(CONF_WATER_INLET): binary_sensor.binary_sensor_schema(
|
||||
# device_class=DEVICE_CLASS_PROBLEM,
|
||||
# icon=ICON_WATER_OFF
|
||||
# ),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
pin_clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN])
|
||||
cg.add(var.set_pin_clock(pin_clock))
|
||||
pin_data = await cg.gpio_pin_expression(config[CONF_DATA_PIN])
|
||||
cg.add(var.set_pin_data(pin_data))
|
||||
if CONF_EN_7SEG_PIN in config:
|
||||
pin_en_7seg = await cg.gpio_pin_expression(config[CONF_EN_7SEG_PIN])
|
||||
cg.add(var.set_pin_en_7seg(pin_en_7seg))
|
||||
if CONF_TIME_REMAINING in config:
|
||||
sens = await sensor.new_sensor(config[CONF_TIME_REMAINING])
|
||||
cg.add(var.set_time_remaining_sensor(sens))
|
||||
if CONF_EN_LAMPS_PIN in config:
|
||||
pin_en_lamps = await cg.gpio_pin_expression(config[CONF_EN_LAMPS_PIN])
|
||||
cg.add(var.set_pin_en_lamps(pin_en_lamps))
|
||||
if CONF_ACTIVE in config:
|
||||
sens = await binary_sensor.new_binary_sensor(config[CONF_ACTIVE])
|
||||
cg.add(var.set_active_sensor(sens))
|
||||
if CONF_CURRENT_OPERATION in config:
|
||||
sens = await text_sensor.new_text_sensor(config[CONF_CURRENT_OPERATION])
|
||||
cg.add(var.set_current_operation_sensor(sens))
|
||||
41
hosts/iron/services/esphome/devices/waschmaschine.yaml
Normal file
41
hosts/iron/services/esphome/devices/waschmaschine.yaml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
esphome:
|
||||
name: "waschmaschine"
|
||||
friendly_name: "Waschmaschine"
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret apikey_waschmaschine
|
||||
|
||||
ota:
|
||||
password: !secret otapass_waschmaschine
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid_bw
|
||||
password: !secret wifi_password_bw
|
||||
domain: .iot.bw.jalr.de
|
||||
|
||||
esp32:
|
||||
board: esp32doit-devkit-v1
|
||||
framework:
|
||||
type: arduino
|
||||
version: recommended
|
||||
|
||||
logger:
|
||||
|
||||
external_components:
|
||||
- source: components
|
||||
components: [ miele_w433 ]
|
||||
|
||||
sensor:
|
||||
- platform: miele_w433
|
||||
enable_7segment_pin: 27
|
||||
clock_pin: 14
|
||||
enable_lamps_pin: 26
|
||||
data_pin: 13
|
||||
time_remaining:
|
||||
name: "verbleibende Zeit"
|
||||
active:
|
||||
name: "in Betrieb"
|
||||
current_operation:
|
||||
name: "aktueller Vorgang"
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue