Skip to content

Commit

Permalink
Add Memory Utils
Browse files Browse the repository at this point in the history
  • Loading branch information
AzonInc committed Sep 23, 2024
1 parent 1bc380f commit 2ff4e05
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 3 deletions.
57 changes: 54 additions & 3 deletions components/tc_bus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"TCBusSendAction", automation.Action
)

TCBusUpdateSettingAction = tc_bus_ns.class_(
"TCBusUpdateSettingAction", automation.Action
)

TCBusProgrammingModeAction = tc_bus_ns.class_(
"TCBusProgrammingModeAction", automation.Action
)
Expand All @@ -22,11 +26,21 @@
"TCBusReadMemoryAction", automation.Action
)

CommandData = tc_bus_ns.struct(f"CommandData")
SettingData = tc_bus_ns.struct(f"SettingData")

ReadMemoryCompleteTrigger = tc_bus_ns.class_("ReadMemoryCompleteTrigger", automation.Trigger.template())
ReadMemoryTimeoutTrigger = tc_bus_ns.class_("ReadMemoryTimeoutTrigger", automation.Trigger.template())

ReceivedCommandTrigger = tc_bus_ns.class_("ReceivedCommandTrigger", automation.Trigger.template())
CommandData = tc_bus_ns.struct(f"CommandData")

SettingType = tc_bus_ns.enum("Setting_Type")
SETTING_TYPES = {
"ringtone_floor_call": SettingType.SETTING_RINGTONE_FLOOR_CALL,
"ringtone_door_call": SettingType.SETTING_RINGTONE_DOOR_CALL,
"ringtone_internal_call": SettingType.SETTING_RINGTONE_INTERNAL_CALL,
"volume_ringtone": SettingType.SETTING_RINGTONE_VOLUME,
"volume_handset": SettingType.SETTING_HANDSET_VOLUME
}

CommandType = tc_bus_ns.enum("Command_Type")
COMMAND_TYPES = {
Expand Down Expand Up @@ -55,7 +69,7 @@
"programming_mode": CommandType.COMMAND_TYPE_PROGRAMMING_MODE,
"read_memory_block": CommandType.COMMAND_TYPE_READ_MEMORY_BLOCK,
"select_memory_page": CommandType.COMMAND_TYPE_SELECT_MEMORY_PAGE,
"write_memory": CommandType.COMMAND_TYPE_WRITE_MEMORY,
"write_memory": CommandType.COMMAND_TYPE_WRITE_MEMORY
}

CONF_TC_ID = "tc_bus"
Expand All @@ -73,6 +87,8 @@
CONF_PAYLOAD = "payload"
CONF_PAYLOAD_LAMBDA = "payload_lambda"

CONF_VALUE = "value"

CONF_BUS_COMMAND = "bus_command"
CONF_HARDWARE_VERSION = "hardware_version"
CONF_DOOR_READINESS = "door_readiness"
Expand Down Expand Up @@ -230,6 +246,41 @@ async def tc_bus_send_to_code(config, action_id, template_args, args):
return var



TC_BUS_UPDATE_SETTING_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.use_id(TCBus),
cv.Required(CONF_TYPE): cv.templatable(cv.enum(SETTING_TYPES, upper=False)),
cv.Required(CONF_ADDRESS): cv.templatable(cv.hex_uint8_t),
cv.Required(CONF_SERIAL_NUMBER): cv.templatable(cv.hex_uint32_t),
})
)

@automation.register_action(
"tc_bus.update_setting",
TCBusUpdateSettingAction,
TC_BUS_UPDATE_SETTING_SCHEMA
)
async def tc_bus_update_setting_to_code(config, action_id, template_args, args):
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_args, parent)

if CONF_TYPE in config:
type_template_ = await cg.templatable(config[CONF_TYPE], args, SettingType)
cg.add(var.set_type(type_template_))

if CONF_VALUE in config:
value_template_ = await cg.templatable(config[CONF_VALUE], args, cg.uint8)
cg.add(var.set_value(value_template_))

if CONF_SERIAL_NUMBER in config:
serial_number_template_ = await cg.templatable(config[CONF_SERIAL_NUMBER], args, cg.uint32)
cg.add(var.set_serial_number(serial_number_template_))

return var


@automation.register_action(
"tc_bus.set_programming_mode",
TCBusProgrammingModeAction,
Expand Down
17 changes: 17 additions & 0 deletions components/tc_bus/automation.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,23 @@ namespace esphome
TCBusComponent *parent_;
};

template<typename... Ts> class TCBusUpdateSettingAction : public Action<Ts...>
{
public:
TCBusUpdateSettingAction(TCBusComponent *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(SettingType, type)
TEMPLATABLE_VALUE(uint32_t, serial_number)
TEMPLATABLE_VALUE(uint8_t, value)

void play(Ts... x)
{
this->parent_->update_setting(this->type_.value(x...), this->value_.value(x...), this->serial_number_.value(x...));
}

protected:
TCBusComponent *parent_;
};

template<typename... Ts> class TCBusProgrammingModeAction : public Action<Ts...>
{
public:
Expand Down
25 changes: 25 additions & 0 deletions components/tc_bus/memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include "esphome/core/hal.h"

namespace esphome
{
namespace tc_bus
{
enum SettingType {
SETTING_RINGTONE_FLOOR_CALL,
SETTING_RINGTONE_DOOR_CALL,
SETTING_RINGTONE_INTERNAL_CALL,
SETTING_RINGTONE_VOLUME,
SETTING_HANDSET_VOLUME
};

struct Settings {
uint8_t handset_volume = 4;
uint8_t ringtone_volume = 4;
uint8_t door_call_ringtone = 0;
uint8_t internal_call_ringtone = 0;
uint8_t floor_call_ringtone = 0;
};
}
}
8 changes: 8 additions & 0 deletions components/tc_bus/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ namespace esphome
COMMAND_TYPE_WRITE_MEMORY
};

enum SettingType {
SETTING_RINGTONE_FLOOR_CALL,
SETTING_RINGTONE_DOOR_CALL,
SETTING_RINGTONE_INTERNAL_CALL,
SETTING_RINGTONE_VOLUME,
SETTING_HANDSET_VOLUME
};

struct CommandData {
uint32_t command;
std::string command_hex;
Expand Down
130 changes: 130 additions & 0 deletions components/tc_bus/tc_bus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ namespace esphome
reading_memory_ = false;
reading_memory_timer_ = 0;

// Save Settings values
settings->handset_volume = memory_buffer_[21] & 0xF;
settings->ringtone_volume = memory_buffer_[20] & 0xF;
settings->door_call_ringtone = (memory_buffer_[3] >> 4) & 0xF;
settings->internal_call_ringtone = (memory_buffer_[6] >> 4) & 0xF;
settings->floor_call_ringtone = (memory_buffer_[9] >> 4) & 0xF;

this->read_memory_complete_callback_.call(memory_buffer_);
}
else
Expand Down Expand Up @@ -616,5 +623,128 @@ namespace esphome
send_command(COMMAND_TYPE_READ_MEMORY_BLOCK, reading_memory_count_);
}

void TCBusComponent::update_setting(SettingType type, uint8_t new_value, uint32_t serial_number)
{
if(memory_buffer_.size() == 0)
{
ESP_LOGW(TAG, "Memory Buffer is empty! Please read memory first!");
return;
}

if(serial_number == 0)
{
serial_number = this->serial_number_;
if (serial_number_lambda_.has_value()) {
auto optional_value = (*serial_number_lambda_)();
if (optional_value.has_value()) {
serial_number = optional_value.value();
}
}
}

if(serial_number == 0)
{
ESP_LOGW(TAG, "Serial Number is not set!");
return;
}

// Prepare Transmission
ESP_LOGD(TAG, "Select Indoor Stations");
send_command(COMMAND_TYPE_SELECT_DEVICE_GROUP, 0, 0); // payload 0 = indoor stations
delay(50);

ESP_LOGD(TAG, "Select Memory Page %i of Serial Number %i", 0, serial_number);
send_command(COMMAND_TYPE_SELECT_MEMORY_PAGE, 0, 0, serial_number);
delay(50);

uint8_t index = 0;

switch(type)
{
case SETTING_RINGTONE_DOOR_CALL:
index = 3;
uint8_t cell2 = memory_buffer_[index] & 0xF;
memory_buffer_[index] = (new_value << 4) | (cell2 & 0xF);
settings->door_call_ringtone = new_value;
break;

case SETTING_RINGTONE_INTERNAL_CALL:
index = 6;
uint8_t cell2 = memory_buffer_[index] & 0xF;
memory_buffer_[index] = (new_value << 4) | (cell2 & 0xF);
settings->internal_call_ringtone = new_value;
break;

case SETTING_RINGTONE_FLOOR_CALL:
index = 9;
uint8_t cell2 = memory_buffer_[index] & 0xF;
memory_buffer_[index] = (new_value << 4) | (cell2 & 0xF);
settings->floor_call_ringtone = new_value;
break;

case SETTING_RINGTONE_VOLUME:
index = 20;
uint8_t cell1 = (memory_buffer_[index] >> 4) & 0xF;
memory_buffer_[index] = (cell1 << 4) | (new_value & 0xF);
settings->ringtone_volume = new_value;
break;

case SETTING_HANDSET_VOLUME:
index = 21;
uint8_t cell1 = (memory_buffer_[index] >> 4) & 0xF;
memory_buffer_[index] = (cell1 << 4) | (new_value & 0xF);
settings->handset_volume = new_value;
break;
}

uint16_t new_values = (memory_buffer_[index] << 8) | memory_buffer_[index + 1];
send_command(COMMAND_TYPE_WRITE_MEMORY, index, new_values, serial_number);
}

void TCBusComponent::write_memory(uint32_t serial_number)
{
if(memory_buffer_.size() == 0)
{
ESP_LOGW(TAG, "Memory Buffer is empty! Please read memory first!");
return;
}

if(serial_number == 0)
{
serial_number = this->serial_number_;
if (serial_number_lambda_.has_value()) {
auto optional_value = (*serial_number_lambda_)();
if (optional_value.has_value()) {
serial_number = optional_value.value();
}
}
}

if(serial_number == 0)
{
ESP_LOGW(TAG, "Serial Number is not set!");
return;
}

// Prepare Transmission
ESP_LOGD(TAG, "Select Indoor Stations");
send_command(COMMAND_TYPE_SELECT_DEVICE_GROUP, 0, 0); // payload 0 = indoor stations
delay(50);

ESP_LOGD(TAG, "Select Memory Page %i of Serial Number %i", 0, serial_number);
send_command(COMMAND_TYPE_SELECT_MEMORY_PAGE, 0, 0, serial_number);
delay(50);

// Transmit Memory
uint8_t address = 0;
for (size_t i = 0; i < memory_buffer_.size(); i += 2)
{
uint16_t new_value = (memory_buffer_[i] << 8) | memory_buffer_[i + 1];
send_command(COMMAND_TYPE_WRITE_MEMORY, address, new_value, serial_number);
address = address + 2;
delay(50);
}
}

} // namespace tc_bus
} // namespace esphome
7 changes: 7 additions & 0 deletions components/tc_bus/tc_bus.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "protocol.h"
#include "memory.h"

#include <utility>
#include <vector>
Expand Down Expand Up @@ -90,6 +91,10 @@ namespace esphome
void read_memory(uint32_t serial_number);
void request_memory_blocks(uint8_t start_address);

void write_memory(uint32_t serial_number = 0);

void update_setting(SettingType type, uint8_t new_value, uint32_t serial_number = 0);

void publish_command(uint32_t command, bool fire_events);

void add_received_command_callback(std::function<void(CommandData)> &&callback);
Expand Down Expand Up @@ -125,6 +130,8 @@ namespace esphome
uint8_t reading_memory_count_ = 0;
uint32_t reading_memory_timer_ = 0;
std::vector<uint8_t> memory_buffer_;

Settings settings;
};

} // namespace tc_bus
Expand Down
19 changes: 19 additions & 0 deletions firmware/addons/memory-utils.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Memory Utils Addon

# Extend TC:BUS Component
tc_bus:
on_read_memory_complete:
- logger.log: "Completed memory reading!"
- lambda: |-
std::string hexString = str_upper_case(format_hex(x));
ESP_LOGD("tcs_bus", "Memory: %s", hexString.c_str());
on_read_memory_timeout:
- logger.log: "Failed to read Memory"


button:
- platform: template
name: "Read Memory"
on_press:
- tc_bus.read_memory:
1 change: 1 addition & 0 deletions firmware/doorman-nuki-bridge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ packages:
device_base: !include base.yaml
pattern_events: !include addons/pattern-events.yaml
ring_to_open: !include addons/ring-to-open.yaml
memory_utils: !include addons/memory-utils.yaml
addon_nuki_bridge: !include addons/nuki-bridge.yaml
interactive_setup: !include addons/interactive-setup.yaml

Expand Down
1 change: 1 addition & 0 deletions firmware/doorman-stock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ packages:
device_base: !include base.yaml
pattern_events: !include addons/pattern-events.yaml
ring_to_open: !include addons/ring-to-open.yaml
memory_utils: !include addons/memory-utils.yaml
interactive_setup: !include addons/interactive-setup.yaml

esp32_improv:
Expand Down

0 comments on commit 2ff4e05

Please sign in to comment.