mirror of
https://github.com/esphome/esphome.git
synced 2025-10-23 12:13:49 +01:00
[zwave_proxy] New component (#10762)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
@@ -548,3 +548,4 @@ esphome/components/xxtea/* @clydebarrow
|
|||||||
esphome/components/zephyr/* @tomaszduda23
|
esphome/components/zephyr/* @tomaszduda23
|
||||||
esphome/components/zhlt01/* @cfeenstra1024
|
esphome/components/zhlt01/* @cfeenstra1024
|
||||||
esphome/components/zio_ultrasonic/* @kahrendt
|
esphome/components/zio_ultrasonic/* @kahrendt
|
||||||
|
esphome/components/zwave_proxy/* @kbx81
|
||||||
|
@@ -66,6 +66,9 @@ service APIConnection {
|
|||||||
rpc voice_assistant_set_configuration(VoiceAssistantSetConfiguration) returns (void) {}
|
rpc voice_assistant_set_configuration(VoiceAssistantSetConfiguration) returns (void) {}
|
||||||
|
|
||||||
rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {}
|
rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {}
|
||||||
|
|
||||||
|
rpc zwave_proxy_frame(ZWaveProxyFrame) returns (void) {}
|
||||||
|
rpc zwave_proxy_request(ZWaveProxyRequest) returns (void) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -254,6 +257,9 @@ message DeviceInfoResponse {
|
|||||||
|
|
||||||
// Top-level area info to phase out suggested_area
|
// Top-level area info to phase out suggested_area
|
||||||
AreaInfo area = 22 [(field_ifdef) = "USE_AREAS"];
|
AreaInfo area = 22 [(field_ifdef) = "USE_AREAS"];
|
||||||
|
|
||||||
|
// Indicates if Z-Wave proxy support is available and features supported
|
||||||
|
uint32 zwave_proxy_feature_flags = 23 [(field_ifdef) = "USE_ZWAVE_PROXY"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListEntitiesRequest {
|
message ListEntitiesRequest {
|
||||||
@@ -2276,3 +2282,26 @@ message UpdateCommandRequest {
|
|||||||
UpdateCommand command = 2;
|
UpdateCommand command = 2;
|
||||||
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== Z-WAVE ====================
|
||||||
|
|
||||||
|
message ZWaveProxyFrame {
|
||||||
|
option (id) = 128;
|
||||||
|
option (source) = SOURCE_BOTH;
|
||||||
|
option (ifdef) = "USE_ZWAVE_PROXY";
|
||||||
|
option (no_delay) = true;
|
||||||
|
|
||||||
|
bytes data = 1 [(fixed_array_size) = 257];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ZWaveProxyRequestType {
|
||||||
|
ZWAVE_PROXY_REQUEST_TYPE_SUBSCRIBE = 0;
|
||||||
|
ZWAVE_PROXY_REQUEST_TYPE_UNSUBSCRIBE = 1;
|
||||||
|
}
|
||||||
|
message ZWaveProxyRequest {
|
||||||
|
option (id) = 129;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_ZWAVE_PROXY";
|
||||||
|
|
||||||
|
ZWaveProxyRequestType type = 1;
|
||||||
|
}
|
||||||
|
@@ -30,6 +30,9 @@
|
|||||||
#ifdef USE_VOICE_ASSISTANT
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
#include "esphome/components/voice_assistant/voice_assistant.h"
|
#include "esphome/components/voice_assistant/voice_assistant.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
#include "esphome/components/zwave_proxy/zwave_proxy.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome::api {
|
namespace esphome::api {
|
||||||
|
|
||||||
@@ -1203,7 +1206,16 @@ void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetCon
|
|||||||
voice_assistant::global_voice_assistant->on_set_configuration(msg.active_wake_words);
|
voice_assistant::global_voice_assistant->on_set_configuration(msg.active_wake_words);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
void APIConnection::zwave_proxy_frame(const ZWaveProxyFrame &msg) {
|
||||||
|
zwave_proxy::global_zwave_proxy->send_frame(msg.data, msg.data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIConnection::zwave_proxy_request(const ZWaveProxyRequest &msg) {
|
||||||
|
zwave_proxy::global_zwave_proxy->zwave_proxy_request(this, msg.type);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
@@ -1460,6 +1472,9 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) {
|
|||||||
#ifdef USE_VOICE_ASSISTANT
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags();
|
resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
resp.zwave_proxy_feature_flags = zwave_proxy::global_zwave_proxy->get_feature_flags();
|
||||||
|
#endif
|
||||||
#ifdef USE_API_NOISE
|
#ifdef USE_API_NOISE
|
||||||
resp.api_encryption_supported = true;
|
resp.api_encryption_supported = true;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -171,6 +171,11 @@ class APIConnection final : public APIServerConnection {
|
|||||||
void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override;
|
void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
void zwave_proxy_frame(const ZWaveProxyFrame &msg) override;
|
||||||
|
void zwave_proxy_request(const ZWaveProxyRequest &msg) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
|
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
|
||||||
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
|
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
|
||||||
|
@@ -129,6 +129,9 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
|
|||||||
#ifdef USE_AREAS
|
#ifdef USE_AREAS
|
||||||
buffer.encode_message(22, this->area);
|
buffer.encode_message(22, this->area);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
buffer.encode_uint32(23, this->zwave_proxy_feature_flags);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
void DeviceInfoResponse::calculate_size(ProtoSize &size) const {
|
void DeviceInfoResponse::calculate_size(ProtoSize &size) const {
|
||||||
#ifdef USE_API_PASSWORD
|
#ifdef USE_API_PASSWORD
|
||||||
@@ -181,6 +184,9 @@ void DeviceInfoResponse::calculate_size(ProtoSize &size) const {
|
|||||||
#ifdef USE_AREAS
|
#ifdef USE_AREAS
|
||||||
size.add_message_object(2, this->area);
|
size.add_message_object(2, this->area);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
size.add_uint32(2, this->zwave_proxy_feature_flags);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer buffer) const {
|
void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
@@ -3013,5 +3019,35 @@ bool UpdateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
bool ZWaveProxyFrame::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
|
switch (field_id) {
|
||||||
|
case 1: {
|
||||||
|
const std::string &data_str = value.as_string();
|
||||||
|
this->data_len = data_str.size();
|
||||||
|
if (this->data_len > 257) {
|
||||||
|
this->data_len = 257;
|
||||||
|
}
|
||||||
|
memcpy(this->data, data_str.data(), this->data_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void ZWaveProxyFrame::encode(ProtoWriteBuffer buffer) const { buffer.encode_bytes(1, this->data, this->data_len); }
|
||||||
|
void ZWaveProxyFrame::calculate_size(ProtoSize &size) const { size.add_length(1, this->data_len); }
|
||||||
|
bool ZWaveProxyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||||
|
switch (field_id) {
|
||||||
|
case 1:
|
||||||
|
this->type = static_cast<enums::ZWaveProxyRequestType>(value.as_uint32());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
@@ -276,6 +276,12 @@ enum UpdateCommand : uint32_t {
|
|||||||
UPDATE_COMMAND_CHECK = 2,
|
UPDATE_COMMAND_CHECK = 2,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
enum ZWaveProxyRequestType : uint32_t {
|
||||||
|
ZWAVE_PROXY_REQUEST_TYPE_SUBSCRIBE = 0,
|
||||||
|
ZWAVE_PROXY_REQUEST_TYPE_UNSUBSCRIBE = 1,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace enums
|
} // namespace enums
|
||||||
|
|
||||||
@@ -492,7 +498,7 @@ class DeviceInfo final : public ProtoMessage {
|
|||||||
class DeviceInfoResponse final : public ProtoMessage {
|
class DeviceInfoResponse final : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t MESSAGE_TYPE = 10;
|
static constexpr uint8_t MESSAGE_TYPE = 10;
|
||||||
static constexpr uint8_t ESTIMATED_SIZE = 247;
|
static constexpr uint8_t ESTIMATED_SIZE = 252;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "device_info_response"; }
|
const char *message_name() const override { return "device_info_response"; }
|
||||||
#endif
|
#endif
|
||||||
@@ -552,6 +558,9 @@ class DeviceInfoResponse final : public ProtoMessage {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef USE_AREAS
|
#ifdef USE_AREAS
|
||||||
AreaInfo area{};
|
AreaInfo area{};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
uint32_t zwave_proxy_feature_flags{0};
|
||||||
#endif
|
#endif
|
||||||
void encode(ProtoWriteBuffer buffer) const override;
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
void calculate_size(ProtoSize &size) const override;
|
void calculate_size(ProtoSize &size) const override;
|
||||||
@@ -2913,5 +2922,40 @@ class UpdateCommandRequest final : public CommandProtoMessage {
|
|||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
class ZWaveProxyFrame final : public ProtoDecodableMessage {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t MESSAGE_TYPE = 128;
|
||||||
|
static constexpr uint8_t ESTIMATED_SIZE = 33;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
const char *message_name() const override { return "z_wave_proxy_frame"; }
|
||||||
|
#endif
|
||||||
|
uint8_t data[257]{};
|
||||||
|
uint16_t data_len{0};
|
||||||
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
|
void calculate_size(ProtoSize &size) const override;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
void dump_to(std::string &out) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
|
};
|
||||||
|
class ZWaveProxyRequest final : public ProtoDecodableMessage {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t MESSAGE_TYPE = 129;
|
||||||
|
static constexpr uint8_t ESTIMATED_SIZE = 2;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
const char *message_name() const override { return "z_wave_proxy_request"; }
|
||||||
|
#endif
|
||||||
|
enums::ZWaveProxyRequestType type{};
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
void dump_to(std::string &out) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
@@ -655,6 +655,18 @@ template<> const char *proto_enum_to_string<enums::UpdateCommand>(enums::UpdateC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
template<> const char *proto_enum_to_string<enums::ZWaveProxyRequestType>(enums::ZWaveProxyRequestType value) {
|
||||||
|
switch (value) {
|
||||||
|
case enums::ZWAVE_PROXY_REQUEST_TYPE_SUBSCRIBE:
|
||||||
|
return "ZWAVE_PROXY_REQUEST_TYPE_SUBSCRIBE";
|
||||||
|
case enums::ZWAVE_PROXY_REQUEST_TYPE_UNSUBSCRIBE:
|
||||||
|
return "ZWAVE_PROXY_REQUEST_TYPE_UNSUBSCRIBE";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void HelloRequest::dump_to(std::string &out) const {
|
void HelloRequest::dump_to(std::string &out) const {
|
||||||
MessageDumpHelper helper(out, "HelloRequest");
|
MessageDumpHelper helper(out, "HelloRequest");
|
||||||
@@ -754,6 +766,9 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
|
|||||||
this->area.dump_to(out);
|
this->area.dump_to(out);
|
||||||
out.append("\n");
|
out.append("\n");
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
dump_field(out, "zwave_proxy_feature_flags", this->zwave_proxy_feature_flags);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
void ListEntitiesRequest::dump_to(std::string &out) const { out.append("ListEntitiesRequest {}"); }
|
void ListEntitiesRequest::dump_to(std::string &out) const { out.append("ListEntitiesRequest {}"); }
|
||||||
void ListEntitiesDoneResponse::dump_to(std::string &out) const { out.append("ListEntitiesDoneResponse {}"); }
|
void ListEntitiesDoneResponse::dump_to(std::string &out) const { out.append("ListEntitiesDoneResponse {}"); }
|
||||||
@@ -2107,6 +2122,18 @@ void UpdateCommandRequest::dump_to(std::string &out) const {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
void ZWaveProxyFrame::dump_to(std::string &out) const {
|
||||||
|
MessageDumpHelper helper(out, "ZWaveProxyFrame");
|
||||||
|
out.append(" data: ");
|
||||||
|
out.append(format_hex_pretty(this->data, this->data_len));
|
||||||
|
out.append("\n");
|
||||||
|
}
|
||||||
|
void ZWaveProxyRequest::dump_to(std::string &out) const {
|
||||||
|
MessageDumpHelper helper(out, "ZWaveProxyRequest");
|
||||||
|
dump_field(out, "type", static_cast<enums::ZWaveProxyRequestType>(this->type));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
|
||||||
|
@@ -588,6 +588,28 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
|||||||
this->on_bluetooth_scanner_set_mode_request(msg);
|
this->on_bluetooth_scanner_set_mode_request(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
case ZWaveProxyFrame::MESSAGE_TYPE: {
|
||||||
|
ZWaveProxyFrame msg;
|
||||||
|
msg.decode(msg_data, msg_size);
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
ESP_LOGVV(TAG, "on_z_wave_proxy_frame: %s", msg.dump().c_str());
|
||||||
|
#endif
|
||||||
|
this->on_z_wave_proxy_frame(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
case ZWaveProxyRequest::MESSAGE_TYPE: {
|
||||||
|
ZWaveProxyRequest msg;
|
||||||
|
msg.decode(msg_data, msg_size);
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
ESP_LOGVV(TAG, "on_z_wave_proxy_request: %s", msg.dump().c_str());
|
||||||
|
#endif
|
||||||
|
this->on_z_wave_proxy_request(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -899,5 +921,19 @@ void APIServerConnection::on_alarm_control_panel_command_request(const AlarmCont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
void APIServerConnection::on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) {
|
||||||
|
if (this->check_authenticated_()) {
|
||||||
|
this->zwave_proxy_frame(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) {
|
||||||
|
if (this->check_authenticated_()) {
|
||||||
|
this->zwave_proxy_request(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
@@ -207,6 +207,12 @@ class APIServerConnectionBase : public ProtoService {
|
|||||||
|
|
||||||
#ifdef USE_UPDATE
|
#ifdef USE_UPDATE
|
||||||
virtual void on_update_command_request(const UpdateCommandRequest &value){};
|
virtual void on_update_command_request(const UpdateCommandRequest &value){};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
virtual void on_z_wave_proxy_frame(const ZWaveProxyFrame &value){};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
virtual void on_z_wave_proxy_request(const ZWaveProxyRequest &value){};
|
||||||
#endif
|
#endif
|
||||||
protected:
|
protected:
|
||||||
void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
|
void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
|
||||||
@@ -335,6 +341,12 @@ class APIServerConnection : public APIServerConnectionBase {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0;
|
virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
virtual void zwave_proxy_frame(const ZWaveProxyFrame &msg) = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
virtual void zwave_proxy_request(const ZWaveProxyRequest &msg) = 0;
|
||||||
#endif
|
#endif
|
||||||
protected:
|
protected:
|
||||||
void on_hello_request(const HelloRequest &msg) override;
|
void on_hello_request(const HelloRequest &msg) override;
|
||||||
@@ -459,6 +471,12 @@ class APIServerConnection : public APIServerConnectionBase {
|
|||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override;
|
void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
void on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ZWAVE_PROXY
|
||||||
|
void on_z_wave_proxy_request(const ZWaveProxyRequest &msg) override;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
43
esphome/components/zwave_proxy/__init__.py
Normal file
43
esphome/components/zwave_proxy/__init__.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import uart
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_ID, CONF_POWER_SAVE_MODE, CONF_WIFI
|
||||||
|
import esphome.final_validate as fv
|
||||||
|
|
||||||
|
CODEOWNERS = ["@kbx81"]
|
||||||
|
DEPENDENCIES = ["api", "uart"]
|
||||||
|
|
||||||
|
zwave_proxy_ns = cg.esphome_ns.namespace("zwave_proxy")
|
||||||
|
ZWaveProxy = zwave_proxy_ns.class_("ZWaveProxy", cg.Component, uart.UARTDevice)
|
||||||
|
|
||||||
|
|
||||||
|
def final_validate(config):
|
||||||
|
full_config = fv.full_config.get()
|
||||||
|
if (wifi_conf := full_config.get(CONF_WIFI)) and (
|
||||||
|
wifi_conf.get(CONF_POWER_SAVE_MODE).lower() != "none"
|
||||||
|
):
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"{CONF_WIFI} {CONF_POWER_SAVE_MODE} must be set to 'none' when using Z-Wave proxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(ZWaveProxy),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
.extend(uart.UART_DEVICE_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = final_validate
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await uart.register_uart_device(var, config)
|
||||||
|
cg.add_define("USE_ZWAVE_PROXY")
|
224
esphome/components/zwave_proxy/zwave_proxy.cpp
Normal file
224
esphome/components/zwave_proxy/zwave_proxy.cpp
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
#include "zwave_proxy.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/util.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace zwave_proxy {
|
||||||
|
|
||||||
|
static const char *const TAG = "zwave_proxy";
|
||||||
|
|
||||||
|
ZWaveProxy::ZWaveProxy() { global_zwave_proxy = this; }
|
||||||
|
|
||||||
|
void ZWaveProxy::loop() {
|
||||||
|
if (this->response_handler_()) {
|
||||||
|
ESP_LOGV(TAG, "Handled late response");
|
||||||
|
}
|
||||||
|
if (this->api_connection_ != nullptr && (!this->api_connection_->is_connection_setup() || !api_is_connected())) {
|
||||||
|
ESP_LOGW(TAG, "Subscriber disconnected");
|
||||||
|
this->api_connection_ = nullptr; // Unsubscribe if disconnected
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this->available()) {
|
||||||
|
uint8_t byte;
|
||||||
|
if (!this->read_byte(&byte)) {
|
||||||
|
this->status_set_warning("UART read failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->parse_byte_(byte)) {
|
||||||
|
ESP_LOGV(TAG, "Sending to client: %s", YESNO(this->api_connection_ != nullptr));
|
||||||
|
if (this->api_connection_ != nullptr) {
|
||||||
|
// minimize copying to reduce CPU overhead
|
||||||
|
if (this->in_bootloader_) {
|
||||||
|
this->outgoing_proto_msg_.data_len = this->buffer_index_;
|
||||||
|
} else {
|
||||||
|
// If this is a data frame, use frame length indicator + 2 (for SoF + checksum), else assume 1 for ACK/NAK/CAN
|
||||||
|
this->outgoing_proto_msg_.data_len = this->buffer_[0] == ZWAVE_FRAME_TYPE_START ? this->buffer_[1] + 2 : 1;
|
||||||
|
}
|
||||||
|
std::memcpy(this->outgoing_proto_msg_.data, this->buffer_, this->outgoing_proto_msg_.data_len);
|
||||||
|
this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrame::MESSAGE_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->status_clear_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZWaveProxy::dump_config() { ESP_LOGCONFIG(TAG, "Z-Wave Proxy"); }
|
||||||
|
|
||||||
|
void ZWaveProxy::zwave_proxy_request(api::APIConnection *api_connection, api::enums::ZWaveProxyRequestType type) {
|
||||||
|
switch (type) {
|
||||||
|
case api::enums::ZWAVE_PROXY_REQUEST_TYPE_SUBSCRIBE:
|
||||||
|
if (this->api_connection_ != nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Only one API subscription is allowed at a time");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->api_connection_ = api_connection;
|
||||||
|
ESP_LOGV(TAG, "API connection is now subscribed");
|
||||||
|
break;
|
||||||
|
case api::enums::ZWAVE_PROXY_REQUEST_TYPE_UNSUBSCRIBE:
|
||||||
|
if (this->api_connection_ != api_connection) {
|
||||||
|
ESP_LOGV(TAG, "API connection is not subscribed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->api_connection_ = nullptr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "Unknown request type: %d", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZWaveProxy::send_frame(const uint8_t *data, size_t length) {
|
||||||
|
if (length == 1 && data[0] == this->last_response_) {
|
||||||
|
ESP_LOGV(TAG, "Skipping sending duplicate response: 0x%02X", data[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "Sending: %s", format_hex_pretty(data, length).c_str());
|
||||||
|
this->write_array(data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZWaveProxy::parse_byte_(uint8_t byte) {
|
||||||
|
bool frame_completed = false;
|
||||||
|
// Basic parsing logic for received frames
|
||||||
|
switch (this->parsing_state_) {
|
||||||
|
case ZWAVE_PARSING_STATE_WAIT_START:
|
||||||
|
this->parse_start_(byte);
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_WAIT_LENGTH:
|
||||||
|
if (!byte) {
|
||||||
|
ESP_LOGW(TAG, "Invalid LENGTH: %u", byte);
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_SEND_NAK;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "Received LENGTH: %u", byte);
|
||||||
|
this->end_frame_after_ = this->buffer_index_ + byte;
|
||||||
|
ESP_LOGVV(TAG, "Calculated EOF: %u", this->end_frame_after_);
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
this->checksum_ ^= byte;
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_TYPE;
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_WAIT_TYPE:
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
ESP_LOGVV(TAG, "Received TYPE: 0x%02X", byte);
|
||||||
|
this->checksum_ ^= byte;
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_COMMAND_ID;
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_WAIT_COMMAND_ID:
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
ESP_LOGVV(TAG, "Received COMMAND ID: 0x%02X", byte);
|
||||||
|
this->checksum_ ^= byte;
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_PAYLOAD;
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_WAIT_PAYLOAD:
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
this->checksum_ ^= byte;
|
||||||
|
ESP_LOGVV(TAG, "Received PAYLOAD: 0x%02X", byte);
|
||||||
|
if (this->buffer_index_ >= this->end_frame_after_) {
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_CHECKSUM;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_WAIT_CHECKSUM:
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
ESP_LOGVV(TAG, "Received CHECKSUM: 0x%02X", byte);
|
||||||
|
ESP_LOGV(TAG, "Calculated CHECKSUM: 0x%02X", this->checksum_);
|
||||||
|
if (this->checksum_ != byte) {
|
||||||
|
ESP_LOGW(TAG, "Bad checksum: expected 0x%02X, got 0x%02X", this->checksum_, byte);
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_SEND_NAK;
|
||||||
|
} else {
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_SEND_ACK;
|
||||||
|
ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(this->buffer_, this->buffer_index_).c_str());
|
||||||
|
frame_completed = true;
|
||||||
|
}
|
||||||
|
this->response_handler_();
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_READ_BL_MENU:
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
if (!byte) {
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_START;
|
||||||
|
frame_completed = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_SEND_ACK:
|
||||||
|
case ZWAVE_PARSING_STATE_SEND_NAK:
|
||||||
|
break; // Should not happen, handled in loop()
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "Bad parsing state; resetting");
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return frame_completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZWaveProxy::parse_start_(uint8_t byte) {
|
||||||
|
this->buffer_index_ = 0;
|
||||||
|
this->checksum_ = 0xFF;
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_START;
|
||||||
|
switch (byte) {
|
||||||
|
case ZWAVE_FRAME_TYPE_START:
|
||||||
|
ESP_LOGVV(TAG, "Received START");
|
||||||
|
if (this->in_bootloader_) {
|
||||||
|
ESP_LOGD(TAG, "Exited bootloader mode");
|
||||||
|
this->in_bootloader_ = false;
|
||||||
|
}
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_LENGTH;
|
||||||
|
return;
|
||||||
|
case ZWAVE_FRAME_TYPE_BL_MENU:
|
||||||
|
ESP_LOGVV(TAG, "Received BL_MENU");
|
||||||
|
if (!this->in_bootloader_) {
|
||||||
|
ESP_LOGD(TAG, "Entered bootloader mode");
|
||||||
|
this->in_bootloader_ = true;
|
||||||
|
}
|
||||||
|
this->buffer_[this->buffer_index_++] = byte;
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_READ_BL_MENU;
|
||||||
|
return;
|
||||||
|
case ZWAVE_FRAME_TYPE_BL_BEGIN_UPLOAD:
|
||||||
|
ESP_LOGVV(TAG, "Received BL_BEGIN_UPLOAD");
|
||||||
|
break;
|
||||||
|
case ZWAVE_FRAME_TYPE_ACK:
|
||||||
|
ESP_LOGVV(TAG, "Received ACK");
|
||||||
|
break;
|
||||||
|
case ZWAVE_FRAME_TYPE_NAK:
|
||||||
|
ESP_LOGW(TAG, "Received NAK");
|
||||||
|
break;
|
||||||
|
case ZWAVE_FRAME_TYPE_CAN:
|
||||||
|
ESP_LOGW(TAG, "Received CAN");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "Unrecognized START: 0x%02X", byte);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Forward response (ACK/NAK/CAN) back to client for processing
|
||||||
|
if (this->api_connection_ != nullptr) {
|
||||||
|
this->outgoing_proto_msg_.data[0] = byte;
|
||||||
|
this->outgoing_proto_msg_.data_len = 1;
|
||||||
|
this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrame::MESSAGE_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZWaveProxy::response_handler_() {
|
||||||
|
switch (this->parsing_state_) {
|
||||||
|
case ZWAVE_PARSING_STATE_SEND_ACK:
|
||||||
|
this->last_response_ = ZWAVE_FRAME_TYPE_ACK;
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_SEND_CAN:
|
||||||
|
this->last_response_ = ZWAVE_FRAME_TYPE_CAN;
|
||||||
|
break;
|
||||||
|
case ZWAVE_PARSING_STATE_SEND_NAK:
|
||||||
|
this->last_response_ = ZWAVE_FRAME_TYPE_NAK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false; // No response handled
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGVV(TAG, "Sending %s (0x%02X)", this->last_response_ == ZWAVE_FRAME_TYPE_ACK ? "ACK" : "NAK/CAN",
|
||||||
|
this->last_response_);
|
||||||
|
this->write_byte(this->last_response_);
|
||||||
|
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_START;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZWaveProxy *global_zwave_proxy = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
} // namespace zwave_proxy
|
||||||
|
} // namespace esphome
|
73
esphome/components/zwave_proxy/zwave_proxy.h
Normal file
73
esphome/components/zwave_proxy/zwave_proxy.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/api/api_connection.h"
|
||||||
|
#include "esphome/components/api/api_pb2.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/uart/uart.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace zwave_proxy {
|
||||||
|
|
||||||
|
enum ZWaveResponseTypes : uint8_t {
|
||||||
|
ZWAVE_FRAME_TYPE_ACK = 0x06,
|
||||||
|
ZWAVE_FRAME_TYPE_CAN = 0x18,
|
||||||
|
ZWAVE_FRAME_TYPE_NAK = 0x15,
|
||||||
|
ZWAVE_FRAME_TYPE_START = 0x01,
|
||||||
|
ZWAVE_FRAME_TYPE_BL_MENU = 0x0D,
|
||||||
|
ZWAVE_FRAME_TYPE_BL_BEGIN_UPLOAD = 0x43,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ZWaveParsingState : uint8_t {
|
||||||
|
ZWAVE_PARSING_STATE_WAIT_START,
|
||||||
|
ZWAVE_PARSING_STATE_WAIT_LENGTH,
|
||||||
|
ZWAVE_PARSING_STATE_WAIT_TYPE,
|
||||||
|
ZWAVE_PARSING_STATE_WAIT_COMMAND_ID,
|
||||||
|
ZWAVE_PARSING_STATE_WAIT_PAYLOAD,
|
||||||
|
ZWAVE_PARSING_STATE_WAIT_CHECKSUM,
|
||||||
|
ZWAVE_PARSING_STATE_SEND_ACK,
|
||||||
|
ZWAVE_PARSING_STATE_SEND_CAN,
|
||||||
|
ZWAVE_PARSING_STATE_SEND_NAK,
|
||||||
|
ZWAVE_PARSING_STATE_READ_BL_MENU,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ZWaveProxyFeature : uint32_t {
|
||||||
|
FEATURE_ZWAVE_PROXY_ENABLED = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ZWaveProxy : public uart::UARTDevice, public Component {
|
||||||
|
public:
|
||||||
|
ZWaveProxy();
|
||||||
|
|
||||||
|
void loop() override;
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
void zwave_proxy_request(api::APIConnection *api_connection, api::enums::ZWaveProxyRequestType type);
|
||||||
|
api::APIConnection *get_api_connection() { return this->api_connection_; }
|
||||||
|
|
||||||
|
uint32_t get_feature_flags() const { return ZWaveProxyFeature::FEATURE_ZWAVE_PROXY_ENABLED; }
|
||||||
|
|
||||||
|
void send_frame(const uint8_t *data, size_t length);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool parse_byte_(uint8_t byte); // Returns true if frame parsing was completed (a frame is ready in the buffer)
|
||||||
|
void parse_start_(uint8_t byte);
|
||||||
|
bool response_handler_();
|
||||||
|
|
||||||
|
api::APIConnection *api_connection_{nullptr}; // Current subscribed client
|
||||||
|
|
||||||
|
uint8_t buffer_[sizeof(api::ZWaveProxyFrame::data)]; // Fixed buffer for incoming data
|
||||||
|
uint8_t buffer_index_{0}; // Index for populating the data buffer
|
||||||
|
uint8_t checksum_{0}; // Checksum of the frame being parsed
|
||||||
|
uint8_t end_frame_after_{0}; // Payload reception ends after this index
|
||||||
|
uint8_t last_response_{0}; // Last response type sent
|
||||||
|
ZWaveParsingState parsing_state_{ZWAVE_PARSING_STATE_WAIT_START};
|
||||||
|
bool in_bootloader_{false}; // True if the device is detected to be in bootloader mode
|
||||||
|
|
||||||
|
// Pre-allocated message - always ready to send
|
||||||
|
api::ZWaveProxyFrame outgoing_proto_msg_;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ZWaveProxy *global_zwave_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
} // namespace zwave_proxy
|
||||||
|
} // namespace esphome
|
@@ -100,6 +100,7 @@
|
|||||||
#define USE_UART_DEBUGGER
|
#define USE_UART_DEBUGGER
|
||||||
#define USE_UPDATE
|
#define USE_UPDATE
|
||||||
#define USE_VALVE
|
#define USE_VALVE
|
||||||
|
#define USE_ZWAVE_PROXY
|
||||||
|
|
||||||
// Feature flags which do not work for zephyr
|
// Feature flags which do not work for zephyr
|
||||||
#ifndef USE_ZEPHYR
|
#ifndef USE_ZEPHYR
|
||||||
|
15
tests/components/zwave_proxy/common.yaml
Normal file
15
tests/components/zwave_proxy/common.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
wifi:
|
||||||
|
ssid: MySSID
|
||||||
|
password: password1
|
||||||
|
power_save_mode: none
|
||||||
|
|
||||||
|
uart:
|
||||||
|
- id: uart_zwave_proxy
|
||||||
|
tx_pin: ${tx_pin}
|
||||||
|
rx_pin: ${rx_pin}
|
||||||
|
baud_rate: 115200
|
||||||
|
|
||||||
|
api:
|
||||||
|
|
||||||
|
zwave_proxy:
|
||||||
|
id: zw_proxy
|
5
tests/components/zwave_proxy/test.esp32-ard.yaml
Normal file
5
tests/components/zwave_proxy/test.esp32-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO17
|
||||||
|
rx_pin: GPIO16
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/zwave_proxy/test.esp32-c3-ard.yaml
Normal file
5
tests/components/zwave_proxy/test.esp32-c3-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO4
|
||||||
|
rx_pin: GPIO5
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/zwave_proxy/test.esp32-c3-idf.yaml
Normal file
5
tests/components/zwave_proxy/test.esp32-c3-idf.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO4
|
||||||
|
rx_pin: GPIO5
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/zwave_proxy/test.esp32-idf.yaml
Normal file
5
tests/components/zwave_proxy/test.esp32-idf.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO17
|
||||||
|
rx_pin: GPIO16
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/zwave_proxy/test.esp8266-ard.yaml
Normal file
5
tests/components/zwave_proxy/test.esp8266-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO4
|
||||||
|
rx_pin: GPIO5
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/zwave_proxy/test.rp2040-ard.yaml
Normal file
5
tests/components/zwave_proxy/test.rp2040-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
tx_pin: GPIO4
|
||||||
|
rx_pin: GPIO5
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
Reference in New Issue
Block a user