feat(gree-ir): wlasny komponent ESPHome dla klimy Gree
Natywne komponenty gree/coolix nie dzialaly - zla suma kontrolna. Protokol zreverse-engineerowany z 22 ramek IR nagranych z pilota: - bajt0 = tryb+power: cool 0x19, heat 0x4C, fan 0x1B, off 0x44 - bajt1 = temperatura jako (temp-16) - checksum = (lo(b0..b3)+hi(b4..b6)+0x0A)&0xF w gornym nibblu b7 - timingi: hdr 9030/-4460, mark 677, space0 553, space1 1630, gap 19960 Termostat Off/Cool/Heat/Fan, zakres 16-30C, HW: Wemos D1 Mini + Grove IR.
This commit is contained in:
parent
423f871486
commit
f1dbdf514d
5
hardware/esp/ir-ac-ha-integration/.gitignore
vendored
Normal file
5
hardware/esp/ir-ac-ha-integration/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Gitignore settings for ESPHome
|
||||
# This is an example and may include too much for your use-case.
|
||||
# You can modify this file to suit your needs.
|
||||
/.esphome/
|
||||
/secrets.yaml
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import climate, remote_transmitter
|
||||
|
||||
CONF_TRANSMITTER_ID = "transmitter_id"
|
||||
|
||||
gree_ir_ns = cg.esphome_ns.namespace("gree_ir")
|
||||
GreeIR = gree_ir_ns.class_("GreeIR", climate.Climate, cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = climate.climate_schema(GreeIR).extend({
|
||||
cv.Required(CONF_TRANSMITTER_ID): cv.use_id(
|
||||
remote_transmitter.RemoteTransmitterComponent
|
||||
),
|
||||
}).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = await climate.new_climate(config)
|
||||
await cg.register_component(var, config)
|
||||
tx = await cg.get_variable(config[CONF_TRANSMITTER_ID])
|
||||
cg.add(var.set_transmitter(tx))
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
#pragma once
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/climate/climate.h"
|
||||
#include "esphome/components/remote_transmitter/remote_transmitter.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gree_ir {
|
||||
|
||||
class GreeIR : public climate::Climate, public Component {
|
||||
public:
|
||||
void set_transmitter(remote_transmitter::RemoteTransmitterComponent *tx) {
|
||||
this->transmitter_ = tx;
|
||||
}
|
||||
|
||||
void setup() override {
|
||||
this->mode = climate::CLIMATE_MODE_OFF;
|
||||
this->target_temperature = 24;
|
||||
this->publish_state();
|
||||
}
|
||||
|
||||
climate::ClimateTraits traits() override {
|
||||
auto traits = climate::ClimateTraits();
|
||||
traits.set_supported_modes({
|
||||
climate::CLIMATE_MODE_OFF,
|
||||
climate::CLIMATE_MODE_COOL,
|
||||
climate::CLIMATE_MODE_HEAT,
|
||||
climate::CLIMATE_MODE_FAN_ONLY,
|
||||
});
|
||||
traits.set_visual_min_temperature(16);
|
||||
traits.set_visual_max_temperature(30);
|
||||
traits.set_visual_temperature_step(1);
|
||||
return traits;
|
||||
}
|
||||
|
||||
void control(const climate::ClimateCall &call) override {
|
||||
if (call.get_mode().has_value())
|
||||
this->mode = *call.get_mode();
|
||||
if (call.get_target_temperature().has_value())
|
||||
this->target_temperature = *call.get_target_temperature();
|
||||
this->transmit_state_();
|
||||
this->publish_state();
|
||||
}
|
||||
|
||||
protected:
|
||||
remote_transmitter::RemoteTransmitterComponent *transmitter_{nullptr};
|
||||
|
||||
void transmit_state_() {
|
||||
uint8_t b[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t mode_byte, b2, b1_0;
|
||||
switch (this->mode) {
|
||||
case climate::CLIMATE_MODE_COOL: mode_byte = 0x19; b2 = 0x60; b1_0 = 0x06; break;
|
||||
case climate::CLIMATE_MODE_HEAT: mode_byte = 0x4C; b2 = 0x40; b1_0 = 0x01; break;
|
||||
case climate::CLIMATE_MODE_FAN_ONLY: mode_byte = 0x1B; b2 = 0x60; b1_0 = 0x02; break;
|
||||
default: mode_byte = 0x44; b2 = 0x00; b1_0 = 0x01; break;
|
||||
}
|
||||
int temp = (int) this->target_temperature;
|
||||
if (temp < 16) temp = 16;
|
||||
if (temp > 30) temp = 30;
|
||||
uint8_t t = (this->mode == climate::CLIMATE_MODE_OFF) ? 0x0A : (uint8_t)(temp - 16);
|
||||
|
||||
b[0] = mode_byte; b[1] = t; b[2] = b2; b[3] = 0x50;
|
||||
b[4] = b1_0; b[5] = 0x00; b[6] = 0x00;
|
||||
uint8_t cs = ((b[0] & 0xF) + (b[1] & 0xF) + (b[2] & 0xF) + (b[3] & 0xF) +
|
||||
((b[4] >> 4) & 0xF) + ((b[5] >> 4) & 0xF) + ((b[6] >> 4) & 0xF) + 0x0A) & 0xF;
|
||||
b[7] = (cs << 4) & 0xF0;
|
||||
|
||||
auto transmit = this->transmitter_->transmit();
|
||||
auto *data = transmit.get_data();
|
||||
data->set_carrier_frequency(38000);
|
||||
const int MK = 677, S0 = 553, S1 = 1630, GAP = 19960;
|
||||
data->mark(9030); data->space(4460);
|
||||
for (int by = 0; by < 4; by++)
|
||||
for (int bit = 0; bit < 8; bit++) { data->mark(MK); data->space(((b[by] >> bit) & 1) ? S1 : S0); }
|
||||
const int foot[3] = {0, 1, 0};
|
||||
for (int i = 0; i < 3; i++) { data->mark(MK); data->space(foot[i] ? S1 : S0); }
|
||||
data->mark(MK); data->space(GAP);
|
||||
for (int by = 4; by < 8; by++)
|
||||
for (int bit = 0; bit < 8; bit++) { data->mark(MK); data->space(((b[by] >> bit) & 1) ? S1 : S0); }
|
||||
data->mark(MK);
|
||||
transmit.perform();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gree_ir
|
||||
} // namespace
|
||||
|
|
@ -1,31 +1,33 @@
|
|||
esphome:
|
||||
name: gree-ir-blaster
|
||||
friendly_name: Gree IR Blaster
|
||||
|
||||
esp8266:
|
||||
board: d1_mini
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: components
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
ap:
|
||||
ssid: "Gree-IR Fallback"
|
||||
password: !secret fallback_password
|
||||
|
||||
logger:
|
||||
api:
|
||||
ota:
|
||||
platform: esphome
|
||||
|
||||
remote_transmitter:
|
||||
id: tx
|
||||
pin: D5
|
||||
carrier_duty_percent: 50%
|
||||
remote_receiver:
|
||||
pin:
|
||||
number: D6
|
||||
inverted: true
|
||||
mode:
|
||||
input: true
|
||||
pullup: true
|
||||
dump: all
|
||||
|
||||
climate:
|
||||
- platform: gree
|
||||
- platform: gree_ir
|
||||
name: "Klimatyzacja"
|
||||
id: gree_ac
|
||||
model: yan
|
||||
transmitter_id: tx
|
||||
|
|
|
|||
Loading…
Reference in a new issue