Skip to content

Commit

Permalink
Generalize write requests
Browse files Browse the repository at this point in the history
  • Loading branch information
elupus committed Aug 27, 2024
1 parent 75f65d6 commit 7dca781
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 26 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ nibegw:
# Optional port this device will listen to to receive write request. Defaults to 10000
write_port: 10000

# Optional command ports for specific requests.
# ports:
# - address: RMU40_S3
# token: RMU_WRITE
# port: 10001

acknowledge:
- MODBUS40
Expand Down
2 changes: 1 addition & 1 deletion components/nibegw/NibeGwClimate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ enum RmuWriteIndex {
RMU_WRITE_INDEX_END = RMU_WRITE_INDEX_SETPOINT_S4 + 1
};

#define RMU_WRITE_INDEX_SETPOINT_SX(index) (RMU_WRITE_INDEX_SETPOINT_S1 + (index) *2)
#define RMU_WRITE_INDEX_SETPOINT_SX(index) (RMU_WRITE_INDEX_SETPOINT_S1 + (index) * 2)

static const int RMU_DEVICE_VERSION = 0x0103;

Expand Down
31 changes: 22 additions & 9 deletions components/nibegw/NibeGwComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ NibeGwComponent::NibeGwComponent(esphome::GPIOPin *dir_pin) {
std::bind(&NibeGwComponent::callback_msg_received, this, std::placeholders::_1, std::placeholders::_2),
std::bind(&NibeGwComponent::callback_msg_token_received, this, std::placeholders::_1, std::placeholders::_2));

udp_read_.onPacket([this](AsyncUDPPacket packet) { token_request_cache(packet, MODBUS40, READ_TOKEN); });
udp_write_.onPacket([this](AsyncUDPPacket packet) { token_request_cache(packet, MODBUS40, WRITE_TOKEN); });
for (auto &x : requests_sockets_) {
auto address = std::get<0>(x.first);
auto token = std::get<1>(x.first);

x.second.socket->onPacket(
[this, address, token](AsyncUDPPacket packet) { token_request_cache(packet, address, token); });
}
}

static request_data_type dedup(const byte *const data, int len, byte val) {
Expand Down Expand Up @@ -40,10 +45,15 @@ void NibeGwComponent::callback_msg_received(const byte *const data, int len) {
return;
}

/* always sending standard data from modbus read token */
auto &udp = requests_sockets_[request_key_type(MODBUS40, READ_TOKEN)].socket;
if (!udp)
return;

ESP_LOGD(TAG, "UDP Packet with %d bytes to send", len);
for (auto target = udp_targets_.begin(); target != udp_targets_.end(); target++) {
ip_addr_t address = (ip_addr_t) std::get<0>(*target);
if (!udp_read_.writeTo(data, len, &address, std::get<1>(*target))) {
if (!udp.writeTo(data, len, &address, std::get<1>(*target))) {
ESP_LOGW(TAG, "UDP Packet send failed to %s:%d", std::get<0>(*target).str().c_str(), std::get<1>(*target));
}
}
Expand Down Expand Up @@ -124,22 +134,25 @@ void NibeGwComponent::dump_config() {
for (auto address = udp_source_ip_.begin(); address != udp_source_ip_.end(); address++) {
ESP_LOGCONFIG(TAG, " Source: %s", address->str().c_str());
}
ESP_LOGCONFIG(TAG, " Read Port: %d", udp_read_port_);
ESP_LOGCONFIG(TAG, " Write Port: %d", udp_write_port_);
for (auto const &x : requests_sockets_) {
ESP_LOGCONFIG(TAG, " Handler %x:%x Port: %d", std::get<0>(x.first), std::get<1>(x.first), x.second.port);
}
}

void NibeGwComponent::loop() {
if (network::is_connected() && !is_connected_) {
ESP_LOGI(TAG, "Connecting network ports.");
udp_read_.listen(udp_read_port_);
udp_write_.listen(udp_write_port_);
for (auto &x : requests_sockets_) {
x.second.socket->listen(x.second.port);
}
is_connected_ = true;
}

if (!network::is_connected() && is_connected_) {
ESP_LOGI(TAG, "Disconnecting network ports.");
udp_read_.close();
udp_write_.close();
for (auto &x : requests_sockets_) {
x.second.socket->close();
}
is_connected_ = false;
}

Expand Down
24 changes: 19 additions & 5 deletions components/nibegw/NibeGwComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>
#include <cstddef>
#include <map>
#include <memory>

#include "esphome.h"
#include "esphome/core/component.h"
Expand Down Expand Up @@ -38,22 +39,24 @@ class NibeGwComponent : public esphome::Component, public esphome::uart::UARTDev
}
const char *TAG = "nibegw";
const int requests_queue_max = 3;
int udp_read_port_ = 9999;
int udp_write_port_ = 10000;

std::vector<network::IPAddress> udp_source_ip_;
bool is_connected_ = false;

struct request_socket_type {
int port;
std::unique_ptr<AsyncUDP> socket;
};

std::vector<target_type> udp_targets_;
std::map<request_key_type, std::queue<request_data_type>> requests_;
std::map<request_key_type, request_provider_type> requests_provider_;
std::map<request_key_type, request_socket_type> requests_sockets_;
std::map<request_key_type, message_listener_type> message_listener_;
HighFrequencyLoopRequester high_freq_;

NibeGw *gw_;

AsyncUDP udp_read_;
AsyncUDP udp_write_;

void callback_msg_received(const byte *const data, int len);
int callback_msg_token_received(eTokenType token, byte *data);
void callback_debug(byte verbose, char *data);
Expand All @@ -68,6 +71,12 @@ class NibeGwComponent : public esphome::Component, public esphome::uart::UARTDev
udp_write_port_ = port;
};

void add_socket_request(int address, int token, int port) {
auto &handler = requests_sockets_[request_key_type(address, token)];
handler.port = port;
handler.socket = make_unique<AsyncUDP>();
}

void add_target(const network::IPAddress &ip, int port) {
auto target = target_type(ip, port);
udp_targets_.push_back(target);
Expand Down Expand Up @@ -97,6 +106,11 @@ class NibeGwComponent : public esphome::Component, public esphome::uart::UARTDev
queue.push(std::move(request));
}

void add_acknowledge(int address) {
gw_->setSendAcknowledge(1);
gw_->setAcknowledge(address, true);
}

NibeGw &gw() {
return *gw_;
}
Expand Down
35 changes: 24 additions & 11 deletions components/nibegw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ID
from esphome.const import (
CONF_ID,
CONF_PORT,
)
from esphome import pins
from esphome.core import CORE
from esphome.components.network import IPAddress
Expand All @@ -28,6 +31,7 @@
CONF_ACKNOWLEDGE_SMS40 = "sms40"
CONF_READ_PORT = "read_port"
CONF_WRITE_PORT = "write_port"
CONF_PORTS = "ports"
CONF_SOURCE = "source"
CONF_ADDRESS = "address"
CONF_TOKEN = "token"
Expand Down Expand Up @@ -76,12 +80,21 @@ def real_enum(enum: Enum):
}
)

PORTS_SCHEMA = cv.Schema(
{
cv.Required(CONF_PORT): cv.port,
cv.Required(CONF_ADDRESS): cv.Any(real_enum(Addresses), int),
cv.Required(CONF_TOKEN): cv.Any(real_enum(Token), int),
}
)

UDP_SCHEMA = cv.Schema(
{
cv.Required(CONF_TARGET, []): cv.ensure_list(TARGET_SCHEMA),
cv.Optional(CONF_SOURCE, []): cv.ensure_list(cv.ipv4),
cv.Optional(CONF_READ_PORT, default=9999): cv.port,
cv.Optional(CONF_WRITE_PORT, default=10000): cv.port,
cv.Optional(CONF_SOURCE, []): cv.ensure_list(cv.ipv4)
cv.Optional(CONF_PORTS, []): cv.ensure_list(PORTS_SCHEMA)
}
)

Expand Down Expand Up @@ -120,19 +133,19 @@ async def to_code(config):
if udp := config.get(CONF_UDP):
for target in udp[CONF_TARGET]:
cg.add(var.add_target(IPAddress(*target[CONF_TARGET_IP].args), target[CONF_TARGET_PORT]))
cg.add(var.set_read_port(udp[CONF_READ_PORT]))
cg.add(var.set_write_port(udp[CONF_WRITE_PORT]))

for port in udp[CONF_PORTS]:
cg.add(var.add_socket_request(port[CONF_ADDRESS], port[CONF_TOKEN], port[CONF_PORT]))
if port_number := udp[CONF_READ_PORT]:
cg.add(var.add_socket_request(Addresses.MODBUS40.value, Token.MODBUS_READ.value, port_number))
if port_number := udp[CONF_WRITE_PORT]:
cg.add(var.add_socket_request(Addresses.MODBUS40.value, Token.MODBUS_WRITE.value, port_number))

for source in udp[CONF_SOURCE]:
cg.add(var.add_source_ip(IPAddress(*source.args)))

if config[CONF_ACKNOWLEDGE]:
cg.add(var.gw().setSendAcknowledge(1))
for address in config[CONF_ACKNOWLEDGE]:
cg.add(
var.gw().setAcknowledge(address, True)
)
else:
cg.add(var.gw().setSendAcknowledge(0))
cg.add(var.add_acknowledge(address))


def xor8(data: bytes) -> int:
Expand Down

0 comments on commit 7dca781

Please sign in to comment.