@@ -54,9 +54,40 @@ void VotronicBle::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t
5454 }
5555 this ->char_solar_charger_handle_ = 0 ;
5656
57+ if (this ->char_bulk_data_handle_ != 0 ) {
58+ auto status = esp_ble_gattc_unregister_for_notify (
59+ this ->parent ()->get_gattc_if (), this ->parent ()->get_remote_bda (), this ->char_bulk_data_handle_ );
60+ if (status) {
61+ ESP_LOGW (TAG , " esp_ble_gattc_unregister_for_notify failed, status=%d" , status);
62+ }
63+ }
64+ this ->char_bulk_data_handle_ = 0 ;
65+ this ->bulk_data_receiving_ = false ;
66+ this ->bulk_data_frames_ .clear ();
67+
5768 break ;
5869 }
5970 case ESP_GATTC_SEARCH_CMPL_EVT : {
71+ // [60:A4:23:91:8F:55] ESP_GATTC_SEARCH_CMPL_EVT
72+ // [60:A4:23:91:8F:55] Service UUID: 0x1801
73+ // [60:A4:23:91:8F:55] start_handle: 0x1 end_handle: 0x4
74+ // [60:A4:23:91:8F:55] Service UUID: 0x1800
75+ // [60:A4:23:91:8F:55] start_handle: 0x5 end_handle: 0x9
76+ // [60:A4:23:91:8F:55] Service UUID: 0x180A
77+ // [60:A4:23:91:8F:55] start_handle: 0xa end_handle: 0x10
78+ // [60:A4:23:91:8F:55] Service UUID: 1D14D6EE-FD63-4FA1-BFA4-8F47B42119F0
79+ // [60:A4:23:91:8F:55] start_handle: 0x11 end_handle: 0x13
80+ // [60:A4:23:91:8F:55] Service UUID: D0CB6AA7-8548-46D0-99F8-2D02611E5270
81+ // [60:A4:23:91:8F:55] start_handle: 0x14 end_handle: 0x21
82+ // [60:A4:23:91:8F:55] Service UUID: AE64A924-1184-4554-8BBC-295DB9F2324A
83+ // [60:A4:23:91:8F:55] start_handle: 0x22 end_handle: 0xffff
84+ // [60:A4:23:91:8F:55] characteristic 9A082A4E-5BCC-4B1D-9958-A97CFCCFA5EC, handle 0x16, properties 0x12
85+ // [60:A4:23:91:8F:55] characteristic 971CCEC2-521D-42FD-B570-CF46FE5CEB65, handle 0x19, properties 0x12
86+ // [60:A4:23:91:8F:55] characteristic 9E298E7F-2594-49DE-BE51-39153A6250E4, handle 0x1c, properties 0xa
87+ // [60:A4:23:91:8F:55] characteristic CFA6E099-FA0F-43AA-88D2-4508B986A67F, handle 0x1e, properties 0xa
88+ // [60:A4:23:91:8F:55] characteristic D2296045-A715-4458-850F-0800C7E11CEC, handle 0x20, properties 0x1a
89+ // [60:A4:23:91:8F:55] gattc_event_handler: event=18 gattc_if=3
90+ // [60:A4:23:91:8F:55] cfg_mtu status 0, mtu 247
6091 auto *char_battery_computer =
6192 this ->parent_ ->get_characteristic (this ->service_monitoring_uuid_ , this ->char_battery_computer_uuid_ );
6293 if (char_battery_computer == nullptr ) {
@@ -87,6 +118,28 @@ void VotronicBle::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t
87118 ESP_LOGW (TAG , " esp_ble_gattc_register_for_notify failed, status=%d" , status2);
88119 }
89120
121+ auto *char_management =
122+ this ->parent_ ->get_characteristic (this ->service_monitoring_uuid_ , this ->char_management_uuid_ );
123+ if (char_management == nullptr ) {
124+ ESP_LOGW (TAG , " [%s] No management characteristic found at device." , this ->parent_ ->address_str ());
125+ break ;
126+ }
127+ this ->char_management_handle_ = char_management->handle ;
128+
129+ auto *char_bulk_data =
130+ this ->parent_ ->get_characteristic (this ->service_log_data_uuid_ , this ->char_bulk_data_uuid_ );
131+ if (char_bulk_data == nullptr ) {
132+ ESP_LOGW (TAG , " [%s] No bulk data characteristic found at device." , this ->parent_ ->address_str ());
133+ break ;
134+ }
135+ this ->char_bulk_data_handle_ = char_bulk_data->handle ;
136+
137+ auto status3 = esp_ble_gattc_register_for_notify (this ->parent ()->get_gattc_if (), this ->parent ()->get_remote_bda (),
138+ char_bulk_data->handle );
139+ if (status3) {
140+ ESP_LOGW (TAG , " esp_ble_gattc_register_for_notify failed (bulk data), status=%d" , status3);
141+ }
142+
90143 break ;
91144 }
92145 case ESP_GATTC_REG_FOR_NOTIFY_EVT : {
@@ -114,6 +167,23 @@ void VotronicBle::update() {
114167 }
115168}
116169
170+ bool VotronicBle::send_command (uint8_t command) {
171+ ESP_LOGD (TAG , " Send command: 0x%02X" , command);
172+
173+ uint8_t frame[1 ];
174+ frame[0 ] = command;
175+
176+ auto status = esp_ble_gattc_write_char (this ->parent_ ->get_gattc_if (), this ->parent_ ->get_conn_id (),
177+ this ->char_management_handle_ , sizeof (frame), frame, ESP_GATT_WRITE_TYPE_RSP ,
178+ ESP_GATT_AUTH_REQ_NONE );
179+
180+ if (status) {
181+ ESP_LOGW (TAG , " [%s] esp_ble_gattc_write_char failed, status=%d" , this ->parent_ ->address_str (), status);
182+ }
183+
184+ return (status == 0 );
185+ }
186+
117187void VotronicBle::on_votronic_ble_data (const uint8_t &handle, const std::vector<uint8_t > &data) {
118188 if (handle == this ->char_solar_charger_handle_ ) {
119189 this ->decode_solar_charger_data_ (data);
@@ -125,12 +195,50 @@ void VotronicBle::on_votronic_ble_data(const uint8_t &handle, const std::vector<
125195 return ;
126196 }
127197
198+ if (handle == this ->char_bulk_data_handle_ ) {
199+ this ->decode_bulk_data_ (data);
200+ return ;
201+ }
202+
128203 ESP_LOGW (TAG , " Your device is probably not supported. Please create an issue here: "
129204 " https://github.com/syssi/esphome-votronic/issues" );
130205 ESP_LOGW (TAG , " Please provide the following unhandled message data: %s" ,
131206 format_hex_pretty (&data.front (), data.size ()).c_str ()); // NOLINT
132207}
133208
209+ void VotronicBle::decode_bulk_data_ (const std::vector<uint8_t > &data) {
210+ if (data.empty ())
211+ return ;
212+
213+ if (data[0 ] == 0xAA ) {
214+ ESP_LOGD (TAG , " Bulk data: begin of transmission" );
215+ this ->bulk_data_frames_ .clear ();
216+ this ->bulk_data_receiving_ = true ;
217+ return ;
218+ }
219+
220+ if (data[0 ] == 0xFF ) {
221+ ESP_LOGD (TAG , " Bulk data: end of transmission (%zu frames)" , this ->bulk_data_frames_ .size ());
222+ this ->bulk_data_receiving_ = false ;
223+ for (size_t i = 0 ; i < this ->bulk_data_frames_ .size (); i++) {
224+ const auto &frame = this ->bulk_data_frames_ [i];
225+ ESP_LOGD (TAG , " Frame[%zu]: %s" , i, format_hex_pretty (frame.data (), frame.size ()).c_str ()); // NOLINT
226+ }
227+ this ->bulk_data_frames_ .clear ();
228+ return ;
229+ }
230+
231+ if (!this ->bulk_data_receiving_ ) {
232+ ESP_LOGW (TAG , " Bulk data frame outside transmission: %s" ,
233+ format_hex_pretty (data.data (), data.size ()).c_str ()); // NOLINT
234+ return ;
235+ }
236+
237+ ESP_LOGD (TAG , " Bulk data frame [%zu]: %s" , this ->bulk_data_frames_ .size (),
238+ format_hex_pretty (data.data (), data.size ()).c_str ()); // NOLINT
239+ this ->bulk_data_frames_ .push_back (data);
240+ }
241+
134242void VotronicBle::decode_battery_computer_data_ (const std::vector<uint8_t > &data) {
135243 if (data.size () != 20 ) {
136244 ESP_LOGW (TAG , " Invalid frame size: %zu" , data.size ());
0 commit comments