mirror of
https://github.com/syssi/esphome-votronic.git
synced 2025-07-22 20:20:35 +02:00
Compare commits
2 Commits
79c0236050
...
add-contro
Author | SHA1 | Date | |
---|---|---|---|
|
8c8f77f09a | ||
|
c42093a466 |
@@ -14,6 +14,12 @@ VotronicBle = votronic_ble_ns.class_(
|
||||
"VotronicBle", ble_client.BLEClientNode, cg.PollingComponent
|
||||
)
|
||||
|
||||
VOTRONIC_BLE_COMPONENT_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_VOTRONIC_BLE_ID): cv.use_id(VotronicBle),
|
||||
}
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
|
102
components/votronic_ble/button/__init__.py
Normal file
102
components/votronic_ble/button/__init__.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import button
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ICON, CONF_ID
|
||||
|
||||
from .. import CONF_VOTRONIC_BLE_ID, VOTRONIC_BLE_COMPONENT_SCHEMA, votronic_ble_ns
|
||||
|
||||
DEPENDENCIES = ["votronic_ble"]
|
||||
|
||||
CODEOWNERS = ["@syssi"]
|
||||
|
||||
CONF_RETRIEVE_SETTINGS = "retrieve_settings"
|
||||
CONF_RETRIEVE_DEVICE_INFO = "retrieve_device_info"
|
||||
|
||||
CONF_RETRIEVE_DAILY_OPERATING_STATISTICS = "retrieve_daily_operating_statistics"
|
||||
CONF_RETRIEVE_WEEKLY_OPERATING_STATISTICS = "retrieve_weekly_operating_statistics"
|
||||
CONF_RETRIEVE_MONTHLY_OPERATING_STATISTICS = "retrieve_monthly_operating_statistics"
|
||||
CONF_RETRIEVE_OPERATING_STATISTICS = "retrieve_operating_statistics"
|
||||
CONF_RESET_ACCUMULATOR = "reset_accumulator"
|
||||
|
||||
ICON_RETRIEVE_DAILY_OPERATING_STATISTICS = "mdi:chart-box-outline"
|
||||
ICON_RETRIEVE_WEEKLY_OPERATING_STATISTICS = "mdi:chart-box-outline"
|
||||
ICON_RETRIEVE_MONTHLY_OPERATING_STATISTICS = "mdi:chart-box-outline"
|
||||
ICON_RETRIEVE_OPERATING_STATISTICS = "mdi:chart-box-outline"
|
||||
ICON_RESET_ACCUMULATOR = "mdi:history"
|
||||
|
||||
BUTTONS = {
|
||||
CONF_RETRIEVE_DAILY_OPERATING_STATISTICS: 0x01,
|
||||
CONF_RETRIEVE_WEEKLY_OPERATING_STATISTICS: 0x02,
|
||||
CONF_RETRIEVE_MONTHLY_OPERATING_STATISTICS: 0x03,
|
||||
CONF_RETRIEVE_OPERATING_STATISTICS: 0x04,
|
||||
CONF_RESET_ACCUMULATOR: 0x06,
|
||||
}
|
||||
|
||||
VotronicButton = votronic_ble_ns.class_("VotronicButton", button.Button, cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = VOTRONIC_BLE_COMPONENT_SCHEMA.extend(
|
||||
{
|
||||
cv.Optional(
|
||||
CONF_RETRIEVE_DAILY_OPERATING_STATISTICS
|
||||
): button.BUTTON_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(VotronicButton),
|
||||
cv.Optional(
|
||||
CONF_ICON, default=ICON_RETRIEVE_DAILY_OPERATING_STATISTICS
|
||||
): cv.icon,
|
||||
}
|
||||
).extend(
|
||||
cv.COMPONENT_SCHEMA
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_RETRIEVE_WEEKLY_OPERATING_STATISTICS
|
||||
): button.BUTTON_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(VotronicButton),
|
||||
cv.Optional(
|
||||
CONF_ICON, default=ICON_RETRIEVE_WEEKLY_OPERATING_STATISTICS
|
||||
): cv.icon,
|
||||
}
|
||||
).extend(
|
||||
cv.COMPONENT_SCHEMA
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_RETRIEVE_MONTHLY_OPERATING_STATISTICS
|
||||
): button.BUTTON_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(VotronicButton),
|
||||
cv.Optional(
|
||||
CONF_ICON, default=ICON_RETRIEVE_MONTHLY_OPERATING_STATISTICS
|
||||
): cv.icon,
|
||||
}
|
||||
).extend(
|
||||
cv.COMPONENT_SCHEMA
|
||||
),
|
||||
cv.Optional(CONF_RETRIEVE_OPERATING_STATISTICS): button.BUTTON_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(VotronicButton),
|
||||
cv.Optional(
|
||||
CONF_ICON, default=ICON_RETRIEVE_OPERATING_STATISTICS
|
||||
): cv.icon,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.Optional(CONF_RESET_ACCUMULATOR): button.BUTTON_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(VotronicButton),
|
||||
cv.Optional(CONF_ICON, default=ICON_RESET_ACCUMULATOR): cv.icon,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_VOTRONIC_BLE_ID])
|
||||
for key, address in BUTTONS.items():
|
||||
if key in config:
|
||||
conf = config[key]
|
||||
var = cg.new_Pvariable(conf[CONF_ID])
|
||||
await cg.register_component(var, conf)
|
||||
await button.register_button(var, conf)
|
||||
cg.add(var.set_parent(hub))
|
||||
cg.add(var.set_holding_register(address))
|
14
components/votronic_ble/button/votronic_button.cpp
Normal file
14
components/votronic_ble/button/votronic_button.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "votronic_button.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace votronic_ble {
|
||||
|
||||
static const char *const TAG = "votronic_ble.button";
|
||||
|
||||
void VotronicButton::dump_config() { LOG_BUTTON("", "VotronicBle Button", this); }
|
||||
void VotronicButton::press_action() { this->parent_->send_command(this->holding_register_); }
|
||||
|
||||
} // namespace votronic_ble
|
||||
} // namespace esphome
|
26
components/votronic_ble/button/votronic_button.h
Normal file
26
components/votronic_ble/button/votronic_button.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "../votronic_ble.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/button/button.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace votronic_ble {
|
||||
|
||||
class VotronicBle;
|
||||
class VotronicButton : public button::Button, public Component {
|
||||
public:
|
||||
void set_parent(VotronicBle *parent) { this->parent_ = parent; };
|
||||
void set_holding_register(uint8_t holding_register) { this->holding_register_ = holding_register; };
|
||||
void dump_config() override;
|
||||
void loop() override {}
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
protected:
|
||||
void press_action() override;
|
||||
VotronicBle *parent_;
|
||||
uint8_t holding_register_;
|
||||
};
|
||||
|
||||
} // namespace votronic_ble
|
||||
} // namespace esphome
|
@@ -58,6 +58,26 @@ void VotronicBle::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
// [60:A4:23:91:8F:55] ESP_GATTC_SEARCH_CMPL_EVT
|
||||
// [60:A4:23:91:8F:55] Service UUID: 0x1801
|
||||
// [60:A4:23:91:8F:55] start_handle: 0x1 end_handle: 0x4
|
||||
// [60:A4:23:91:8F:55] Service UUID: 0x1800
|
||||
// [60:A4:23:91:8F:55] start_handle: 0x5 end_handle: 0x9
|
||||
// [60:A4:23:91:8F:55] Service UUID: 0x180A
|
||||
// [60:A4:23:91:8F:55] start_handle: 0xa end_handle: 0x10
|
||||
// [60:A4:23:91:8F:55] Service UUID: 1D14D6EE-FD63-4FA1-BFA4-8F47B42119F0
|
||||
// [60:A4:23:91:8F:55] start_handle: 0x11 end_handle: 0x13
|
||||
// [60:A4:23:91:8F:55] Service UUID: D0CB6AA7-8548-46D0-99F8-2D02611E5270
|
||||
// [60:A4:23:91:8F:55] start_handle: 0x14 end_handle: 0x21
|
||||
// [60:A4:23:91:8F:55] Service UUID: AE64A924-1184-4554-8BBC-295DB9F2324A
|
||||
// [60:A4:23:91:8F:55] start_handle: 0x22 end_handle: 0xffff
|
||||
// [60:A4:23:91:8F:55] characteristic 9A082A4E-5BCC-4B1D-9958-A97CFCCFA5EC, handle 0x16, properties 0x12
|
||||
// [60:A4:23:91:8F:55] characteristic 971CCEC2-521D-42FD-B570-CF46FE5CEB65, handle 0x19, properties 0x12
|
||||
// [60:A4:23:91:8F:55] characteristic 9E298E7F-2594-49DE-BE51-39153A6250E4, handle 0x1c, properties 0xa
|
||||
// [60:A4:23:91:8F:55] characteristic CFA6E099-FA0F-43AA-88D2-4508B986A67F, handle 0x1e, properties 0xa
|
||||
// [60:A4:23:91:8F:55] characteristic D2296045-A715-4458-850F-0800C7E11CEC, handle 0x20, properties 0x1a
|
||||
// [60:A4:23:91:8F:55] gattc_event_handler: event=18 gattc_if=3
|
||||
// [60:A4:23:91:8F:55] cfg_mtu status 0, mtu 247
|
||||
auto *char_battery_computer =
|
||||
this->parent_->get_characteristic(this->service_monitoring_uuid_, this->char_battery_computer_uuid_);
|
||||
if (char_battery_computer == nullptr) {
|
||||
@@ -88,6 +108,14 @@ void VotronicBle::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status2);
|
||||
}
|
||||
|
||||
auto *char_management =
|
||||
this->parent_->get_characteristic(this->service_monitoring_uuid_, this->char_management_uuid_);
|
||||
if (char_management == nullptr) {
|
||||
ESP_LOGW(TAG, "[%s] No management characteristic found at device.", this->parent_->address_str().c_str());
|
||||
break;
|
||||
}
|
||||
this->char_management_handle_ = char_management->handle;
|
||||
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
||||
@@ -115,6 +143,23 @@ void VotronicBle::update() {
|
||||
}
|
||||
}
|
||||
|
||||
bool VotronicBle::send_command(uint8_t command) {
|
||||
ESP_LOGD(TAG, "Send command: 0x%02X", command);
|
||||
|
||||
uint8_t frame[1];
|
||||
frame[0] = command;
|
||||
|
||||
auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
|
||||
this->char_management_handle_, sizeof(frame), frame,
|
||||
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||
}
|
||||
|
||||
return (status == 0);
|
||||
}
|
||||
|
||||
void VotronicBle::on_votronic_ble_data(const uint8_t &handle, const std::vector<uint8_t> &data) {
|
||||
if (handle == this->char_solar_charger_handle_) {
|
||||
this->decode_solar_charger_data_(data);
|
||||
|
@@ -83,6 +83,7 @@ class VotronicBle : public esphome::ble_client::BLEClientNode, public PollingCom
|
||||
|
||||
void on_votronic_ble_data(const uint8_t &handle, const std::vector<uint8_t> &data);
|
||||
void set_throttle(uint32_t throttle) { this->throttle_ = throttle; }
|
||||
bool send_command(uint8_t command);
|
||||
|
||||
protected:
|
||||
binary_sensor::BinarySensor *charging_binary_sensor_;
|
||||
@@ -111,6 +112,7 @@ class VotronicBle : public esphome::ble_client::BLEClientNode, public PollingCom
|
||||
|
||||
uint16_t char_battery_computer_handle_{0x22};
|
||||
uint16_t char_solar_charger_handle_{0x25};
|
||||
uint16_t char_management_handle_{0x24};
|
||||
uint32_t last_battery_computer_data_{0};
|
||||
uint32_t last_solar_charger_data_{0};
|
||||
uint32_t throttle_;
|
||||
@@ -123,12 +125,12 @@ class VotronicBle : public esphome::ble_client::BLEClientNode, public PollingCom
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("ae64a924-1184-4554-8bbc-295db9f2324a");
|
||||
|
||||
esp32_ble_tracker::ESPBTUUID char_battery_computer_uuid_ =
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("9a082a4e-5bcc-4b1d-9958-a97cfccfa5ec");
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("9a082a4e-5bcc-4b1d-9958-a97cfccfa5ec"); // Handle 0x16 (22)
|
||||
esp32_ble_tracker::ESPBTUUID char_solar_charger_uuid_ =
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("971ccec2-521d-42fd-b570-cf46fe5ceb65");
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("971ccec2-521d-42fd-b570-cf46fe5ceb65"); // Handle 0x19 (25)
|
||||
|
||||
esp32_ble_tracker::ESPBTUUID char_management_uuid_ =
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("ac12f485-cab7-4e0a-aac5-3585918852f6");
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("ac12f485-cab7-4e0a-aac5-3585918852f6"); // Handle 0x24 (36)
|
||||
esp32_ble_tracker::ESPBTUUID char_bulk_data_uuid_ =
|
||||
esp32_ble_tracker::ESPBTUUID::from_raw("b8a37ffe-c57b-4007-b3c1-ca05a6b7f0c6");
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
substitutions:
|
||||
name: votronic
|
||||
device_description: "Monitor a votronic device via BLE"
|
||||
external_components_source: github://syssi/esphome-votronic@drop-patched-ble-stack
|
||||
external_components_source: github://syssi/esphome-votronic@add-controls
|
||||
mac_address: 60:A4:23:91:8F:55
|
||||
|
||||
esphome:
|
||||
@@ -76,6 +76,20 @@ binary_sensor:
|
||||
aes_active:
|
||||
name: "${name} aes active"
|
||||
|
||||
button:
|
||||
- platform: votronic_ble
|
||||
votronic_ble_id: votronic0
|
||||
retrieve_daily_operating_statistics:
|
||||
name: "${name} retrieve daily operating statistics"
|
||||
retrieve_weekly_operating_statistics:
|
||||
name: "${name} retrieve weekly operating statistics"
|
||||
retrieve_monthly_operating_statistics:
|
||||
name: "${name} retrieve monthly operating statistics"
|
||||
retrieve_operating_statistics:
|
||||
name: "${name} retrieve operating statistics"
|
||||
reset_accumulator:
|
||||
name: "${name} reset accumulator"
|
||||
|
||||
sensor:
|
||||
- platform: votronic_ble
|
||||
votronic_ble_id: votronic0
|
||||
|
@@ -1,3 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
esphome -s external_components_source components ${1:-run} ${2:-esp32-ble-example-faker.yaml}
|
||||
|
||||
if [[ $2 == tests/* ]]; then
|
||||
C="../components"
|
||||
else
|
||||
C="components"
|
||||
fi
|
||||
|
||||
esphome -s external_components_source $C ${1:-run} ${2:-esp32-ble-example-faker.yaml}
|
||||
|
@@ -1,3 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
esphome -s external_components_source components ${1:-run} ${2:-esp8266-solar-charger-example-faker.yaml}
|
||||
if [[ $2 == tests/* ]]; then
|
||||
C="../components"
|
||||
else
|
||||
C="components"
|
||||
fi
|
||||
|
||||
esphome -s external_components_source $C ${1:-run} ${2:-esp8266-solar-charger-example-faker.yaml}
|
||||
|
Reference in New Issue
Block a user