esphome: name: homey-ir-blaster friendly_name: homey-ir-blaster comment: "Homey IR Blaster for learning and sending remotes" name_add_mac_suffix: false esp8266: board: esp8285 logger: api: encryption: key: !secret homey-ir-blaster__api_key ota: - platform: esphome password: !secret homey-ir-blaster__ota_password wifi: ssid: !secret wifi_ssid password: !secret wifi_password min_auth_mode: WPA2 ap: ssid: "homey-ir-blaster Hotspot" password: !secret homey-ir-blaster__fallback_password captive_portal: globals: # Leere ID = momentan kein Lernvorgang aktiv - id: ir_learn_request_id type: std::string restore_value: no initial_value: '""' - id: ir_learn_frame_count type: int restore_value: no initial_value: '0' - id: ir_learn_max_frames type: int restore_value: no initial_value: '100' mqtt: id: mqtt_client broker: !secret mqtt_broker username: !secret mqtt_username password: !secret mqtt_password on_json_message: - topic: homey/ir/learn qos: 1 then: - lambda: |- if (!x["requestId"].is()) { ESP_LOGW("ir_learn", "Learn request without requestId"); return; } id(ir_learn_request_id) = x["requestId"].as(); id(ir_learn_frame_count) = 0; id(ir_learn_max_frames) = 100; if (x["maxFrames"].is()) { const int requested = x["maxFrames"].as(); if (requested >= 1 && requested <= 250) { id(ir_learn_max_frames) = requested; } } ESP_LOGI( "ir_learn", "Learning started, requestId=%s, maxFrames=%d", id(ir_learn_request_id).c_str(), id(ir_learn_max_frames) ); - topic: homey/ir/learn/stop qos: 1 then: - lambda: |- if (!x["requestId"].is()) { return; } const std::string request_id = x["requestId"].as(); if (request_id != id(ir_learn_request_id)) { return; } ESP_LOGI( "ir_learn", "Learning stopped by Homey, requestId=%s, frames=%d", id(ir_learn_request_id).c_str(), id(ir_learn_frame_count) ); id(ir_learn_request_id).clear(); id(ir_learn_frame_count) = 0; - topic: !secret ir_send_topic qos: 1 then: - lambda: |- if (!x["carrier"].is() || !x["timings"].is()) { ESP_LOGW("ir_send", "Invalid send request: carrier/timings missing"); return; } const int carrier = x["carrier"].as(); int repetitions = 1; if (x["repetitions"].is()) { repetitions = x["repetitions"].as(); } if (carrier < 30000 || carrier > 58000 || repetitions < 1 || repetitions > 20) { ESP_LOGW("ir_send", "Invalid carrier or repetitions"); return; } JsonArrayConst timings = x["timings"].as(); if (timings.size() < 2 || (timings.size() % 2) != 0) { ESP_LOGW("ir_send", "Invalid raw timing count: %u", timings.size()); return; } auto call = id(ir_transmitter).transmit(); auto *data = call.get_data(); data->set_carrier_frequency(carrier); data->reserve(timings.size()); size_t index = 0; for (JsonVariantConst timing_value : timings) { if (!timing_value.is()) { ESP_LOGW("ir_send", "Invalid timing at index %u", index); return; } const int timing = timing_value.as(); if ((index % 2 == 0 && timing <= 0) || (index % 2 == 1 && timing >= 0)) { ESP_LOGW("ir_send", "Invalid timing polarity at index %u", index); return; } if (timing > 0) { data->mark(timing); } else { data->space(-timing); } index += 1; } call.set_send_times(repetitions); call.set_send_wait(0); call.perform(); ESP_LOGI( "ir_send", "IR sent: carrier=%dHz, repetitions=%d, timings=%u", carrier, repetitions, timings.size() ); remote_receiver: id: ir_receiver pin: number: GPIO14 inverted: true dump: - pronto on_pronto: then: - if: condition: lambda: |- return !id(ir_learn_request_id).empty() && id(ir_learn_frame_count) < id(ir_learn_max_frames); then: - mqtt.publish_json: topic: homey/ir/received qos: 1 retain: false payload: |- root["requestId"] = id(ir_learn_request_id); root["format"] = "pronto"; root["code"] = x.data; root["captureIndex"] = id(ir_learn_frame_count) + 1; root["receivedAtMs"] = millis(); root["maxFrames"] = id(ir_learn_max_frames); - lambda: |- id(ir_learn_frame_count) += 1; ESP_LOGI( "ir_learn", "Published Pronto frame %d/%d for requestId=%s", id(ir_learn_frame_count), id(ir_learn_max_frames), id(ir_learn_request_id).c_str() ); if (id(ir_learn_frame_count) >= id(ir_learn_max_frames)) { ESP_LOGW( "ir_learn", "Learning frame safety limit reached, requestId=%s", id(ir_learn_request_id).c_str() ); id(ir_learn_request_id).clear(); id(ir_learn_frame_count) = 0; } remote_transmitter: id: ir_transmitter pin: GPIO4 carrier_duty_percent: 50%