@@ -285,6 +285,105 @@ TEST(SeplosBmsV3BleEicTest, HeatingIsNotAProblem) {
285285 EXPECT_EQ (problem_text.state , " No problems" );
286286}
287287
288+ // ── EIC: event-code sensors and protection binary sensors ─────────────────────
289+
290+ // Raw event-code registers: TB09 state (byte 0), TB02 voltage (byte 1),
291+ // TB05 current (byte 4); the cell-temperature alarm (TB03, byte 2) lands in the
292+ // high byte of the combined temperature code.
293+ TEST (SeplosBmsV3BleEicTest, EventCodeSensors) {
294+ TestableSeplosBmsV3Ble bms;
295+ sensor::Sensor system_state, voltage_code, temperature_code, current_code;
296+ bms.set_system_state_code_sensor (&system_state);
297+ bms.set_voltage_event_code_sensor (&voltage_code);
298+ bms.set_temperature_event_code_sensor (&temperature_code);
299+ bms.set_current_event_code_sensor (¤t_code);
300+
301+ bms.decode_eic (EIC_DATA_WITH_PROBLEM ); // data[2] = 0x01
302+
303+ EXPECT_FLOAT_EQ (system_state.state , 0 .0f );
304+ EXPECT_FLOAT_EQ (voltage_code.state , 0 .0f );
305+ EXPECT_FLOAT_EQ (temperature_code.state , 256 .0f ); // (0x01 << 8) | 0x00
306+ EXPECT_FLOAT_EQ (current_code.state , 0 .0f );
307+ }
308+
309+ // TB03 (cell temperature, high byte) and TB04 (ambient/power temperature, low byte)
310+ // share one temperature event-code sensor; an ambient fault sets the low byte and
311+ // raises temperature protection.
312+ TEST (SeplosBmsV3BleEicTest, TemperatureEventCodeCombinesCellAndAmbient) {
313+ TestableSeplosBmsV3Ble bms;
314+ sensor::Sensor temperature_code;
315+ binary_sensor::BinarySensor temperature_protection;
316+ bms.set_temperature_event_code_sensor (&temperature_code);
317+ bms.set_temperature_protection_binary_sensor (&temperature_protection);
318+
319+ bms.decode_eic (EIC_DATA_AMBIENT_TEMP ); // data[3] = 0x01
320+
321+ EXPECT_FLOAT_EQ (temperature_code.state , 1 .0f ); // (0x00 << 8) | 0x01
322+ EXPECT_TRUE (temperature_protection.state );
323+ }
324+
325+ // The heating status bit (TB04 bit6) is kept in the raw event code but masked out
326+ // of the protection flag.
327+ TEST (SeplosBmsV3BleEicTest, HeatingShowsInCodeButNotProtection) {
328+ TestableSeplosBmsV3Ble bms;
329+ sensor::Sensor temperature_code;
330+ binary_sensor::BinarySensor temperature_protection;
331+ bms.set_temperature_event_code_sensor (&temperature_code);
332+ bms.set_temperature_protection_binary_sensor (&temperature_protection);
333+
334+ bms.decode_eic (EIC_DATA_HEATING ); // data[3] = 0x40
335+
336+ EXPECT_FLOAT_EQ (temperature_code.state , 64 .0f ); // (0x00 << 8) | 0x40, raw byte kept
337+ EXPECT_FALSE (temperature_protection.state ); // 0x40 & 0x3F == 0
338+ }
339+
340+ TEST (SeplosBmsV3BleEicTest, ProtectionBinarySensors) {
341+ TestableSeplosBmsV3Ble bms;
342+ binary_sensor::BinarySensor voltage_protection, temperature_protection, current_protection, system_fault;
343+ bms.set_voltage_protection_binary_sensor (&voltage_protection);
344+ bms.set_temperature_protection_binary_sensor (&temperature_protection);
345+ bms.set_current_protection_binary_sensor (¤t_protection);
346+ bms.set_system_fault_binary_sensor (&system_fault);
347+
348+ bms.decode_eic (EIC_DATA_WITH_PROBLEM ); // data[2] = 0x01 (cell temperature)
349+
350+ EXPECT_FALSE (voltage_protection.state );
351+ EXPECT_TRUE (temperature_protection.state );
352+ EXPECT_FALSE (current_protection.state );
353+ EXPECT_FALSE (system_fault.state );
354+ }
355+
356+ // Hard fault (TB15, byte 9) drives the dedicated system-fault flag.
357+ TEST (SeplosBmsV3BleEicTest, SystemFaultBinarySensor) {
358+ TestableSeplosBmsV3Ble bms;
359+ binary_sensor::BinarySensor system_fault;
360+ bms.set_system_fault_binary_sensor (&system_fault);
361+
362+ bms.decode_eic (EIC_DATA_HARD_FAULT ); // data[9] = 0x02
363+
364+ EXPECT_TRUE (system_fault.state );
365+ }
366+
367+ // Operating-status state code (TB09) is exposed but is not a protection event.
368+ TEST (SeplosBmsV3BleEicTest, SystemStateCodeIsNotProtection) {
369+ TestableSeplosBmsV3Ble bms;
370+ sensor::Sensor system_state;
371+ binary_sensor::BinarySensor voltage_protection, temperature_protection, current_protection, system_fault;
372+ bms.set_system_state_code_sensor (&system_state);
373+ bms.set_voltage_protection_binary_sensor (&voltage_protection);
374+ bms.set_temperature_protection_binary_sensor (&temperature_protection);
375+ bms.set_current_protection_binary_sensor (¤t_protection);
376+ bms.set_system_fault_binary_sensor (&system_fault);
377+
378+ bms.decode_eic (EIC_DATA_STATUS_ONLY ); // data[0] = 0x10
379+
380+ EXPECT_FLOAT_EQ (system_state.state , 16 .0f );
381+ EXPECT_FALSE (voltage_protection.state );
382+ EXPECT_FALSE (temperature_protection.state );
383+ EXPECT_FALSE (current_protection.state );
384+ EXPECT_FALSE (system_fault.state );
385+ }
386+
288387// ── PCT: inverter / protocol sensors ──────────────────────────────────────────
289388
290389TEST (SeplosBmsV3BlePctTest, Sensors) {
@@ -402,6 +501,7 @@ TEST(SeplosBmsV3BleSafetyTest, NullSensorsDoNotCrash) {
402501 EXPECT_NO_FATAL_FAILURE (bms.decode_eib (EIB_DATA ));
403502 EXPECT_NO_FATAL_FAILURE (bms.decode_eic (EIC_DATA_NO_PROBLEM ));
404503 EXPECT_NO_FATAL_FAILURE (bms.decode_eic (EIC_DATA_WITH_PROBLEM ));
504+ EXPECT_NO_FATAL_FAILURE (bms.decode_eic (EIC_DATA_AMBIENT_TEMP ));
405505}
406506
407507} // namespace esphome::seplos_bms_v3_ble::testing
0 commit comments