Skip to content

Commit bb27d0b

Browse files
feat(car): raise the maximum supported cars from 4 to 8
Some users have more than 4 EVs/chargers registered (e.g. multiple Octopus Intelligent devices), which the previous 4-car ceiling (CONFIG_ITEMS entities, KERNEL_MAX_CARS) rejected outright by clamping num_cars down. Doubling the limit to 8 needs three things kept in lockstep: the shared PREDBAT_MAX_CARS constant, the C++ kernel's PK_MAX_CARS array size (with its ABI/parity revision bumped so a stale 4-car binary is safely rejected rather than corrupting the ctypes struct layout), and the matching ctypes.Structure array sizes on the Python side (previously hardcoded to 4 independently of KERNEL_MAX_CARS - this mismatch caused a segfault before the fix). - const.py: PREDBAT_MAX_CARS 4 -> 8 - prediction_kernel.cpp / .py: PK_MAX_CARS/KERNEL_MAX_CARS -> 8, parity revision bumped 5 -> 6, ctypes array fields now reference KERNEL_MAX_CARS instead of a hardcoded 4 - config.py: added car_charging_rate_4..7 and car_charging_manual_soc(_kwh)_4..7 CONFIG_ITEMS entries so cars 4-7 have HA entities to configure - Rebuilt and committed all 6 cross-compiled kernel binaries - Extended regression tests for the new ceiling (kernel parity, 8-car config resolution via the real config_index, MockConfigProvider car rate defaults) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent d37a107 commit bb27d0b

13 files changed

Lines changed: 174 additions & 13 deletions

apps/predbat/config.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,58 @@
322322
"enable": "num_cars",
323323
"enable_condition": "num_cars > 3",
324324
},
325+
{
326+
"name": "car_charging_rate_4",
327+
"friendly_name": "Car charging rate (Car 4)",
328+
"type": "input_number",
329+
"min": 1,
330+
"max": 24,
331+
"step": 0.10,
332+
"unit": "kW",
333+
"icon": "mdi:ev-station",
334+
"default": 7.4,
335+
"enable": "num_cars",
336+
"enable_condition": "num_cars > 4",
337+
},
338+
{
339+
"name": "car_charging_rate_5",
340+
"friendly_name": "Car charging rate (Car 5)",
341+
"type": "input_number",
342+
"min": 1,
343+
"max": 24,
344+
"step": 0.10,
345+
"unit": "kW",
346+
"icon": "mdi:ev-station",
347+
"default": 7.4,
348+
"enable": "num_cars",
349+
"enable_condition": "num_cars > 5",
350+
},
351+
{
352+
"name": "car_charging_rate_6",
353+
"friendly_name": "Car charging rate (Car 6)",
354+
"type": "input_number",
355+
"min": 1,
356+
"max": 24,
357+
"step": 0.10,
358+
"unit": "kW",
359+
"icon": "mdi:ev-station",
360+
"default": 7.4,
361+
"enable": "num_cars",
362+
"enable_condition": "num_cars > 6",
363+
},
364+
{
365+
"name": "car_charging_rate_7",
366+
"friendly_name": "Car charging rate (Car 7)",
367+
"type": "input_number",
368+
"min": 1,
369+
"max": 24,
370+
"step": 0.10,
371+
"unit": "kW",
372+
"icon": "mdi:ev-station",
373+
"default": 7.4,
374+
"enable": "num_cars",
375+
"enable_condition": "num_cars > 7",
376+
},
325377
{
326378
"name": "car_charging_loss",
327379
"friendly_name": "Car charging loss",
@@ -741,6 +793,90 @@
741793
"default": 0.0,
742794
"restore": False,
743795
},
796+
{
797+
"name": "car_charging_manual_soc_4",
798+
"friendly_name": "Car charging manual SOC (Car 4)",
799+
"type": "switch",
800+
"default": False,
801+
"enable": "num_cars",
802+
"enable_condition": "num_cars > 4",
803+
},
804+
{
805+
"name": "car_charging_manual_soc_kwh_4",
806+
"friendly_name": "Car manual SOC kWh (Car 4)",
807+
"type": "input_number",
808+
"min": 0,
809+
"max": 100,
810+
"step": 0.01,
811+
"unit": "kWh",
812+
"icon": "mdi:ev-station",
813+
"enable": "car_charging_manual_soc_4",
814+
"default": 0.0,
815+
"restore": False,
816+
},
817+
{
818+
"name": "car_charging_manual_soc_5",
819+
"friendly_name": "Car charging manual SOC (Car 5)",
820+
"type": "switch",
821+
"default": False,
822+
"enable": "num_cars",
823+
"enable_condition": "num_cars > 5",
824+
},
825+
{
826+
"name": "car_charging_manual_soc_kwh_5",
827+
"friendly_name": "Car manual SOC kWh (Car 5)",
828+
"type": "input_number",
829+
"min": 0,
830+
"max": 100,
831+
"step": 0.01,
832+
"unit": "kWh",
833+
"icon": "mdi:ev-station",
834+
"enable": "car_charging_manual_soc_5",
835+
"default": 0.0,
836+
"restore": False,
837+
},
838+
{
839+
"name": "car_charging_manual_soc_6",
840+
"friendly_name": "Car charging manual SOC (Car 6)",
841+
"type": "switch",
842+
"default": False,
843+
"enable": "num_cars",
844+
"enable_condition": "num_cars > 6",
845+
},
846+
{
847+
"name": "car_charging_manual_soc_kwh_6",
848+
"friendly_name": "Car manual SOC kWh (Car 6)",
849+
"type": "input_number",
850+
"min": 0,
851+
"max": 100,
852+
"step": 0.01,
853+
"unit": "kWh",
854+
"icon": "mdi:ev-station",
855+
"enable": "car_charging_manual_soc_6",
856+
"default": 0.0,
857+
"restore": False,
858+
},
859+
{
860+
"name": "car_charging_manual_soc_7",
861+
"friendly_name": "Car charging manual SOC (Car 7)",
862+
"type": "switch",
863+
"default": False,
864+
"enable": "num_cars",
865+
"enable_condition": "num_cars > 7",
866+
},
867+
{
868+
"name": "car_charging_manual_soc_kwh_7",
869+
"friendly_name": "Car manual SOC kWh (Car 7)",
870+
"type": "input_number",
871+
"min": 0,
872+
"max": 100,
873+
"step": 0.01,
874+
"unit": "kWh",
875+
"icon": "mdi:ev-station",
876+
"enable": "car_charging_manual_soc_7",
877+
"default": 0.0,
878+
"restore": False,
879+
},
744880
{
745881
"name": "octopus_intelligent_charging",
746882
"friendly_name": "Octopus Intelligent Charging",

apps/predbat/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
INVERTER_MAX_RETRY_REST = 5 # Maximum number of retries for inverter REST commands
4141
INVERTER_REST_TIMEOUT = 10 # Seconds to wait for a REST response before giving up (local network call, should be fast)
4242
INVERTER_QUICK_UPDATE_SECONDS = 120 # Minimum seconds between quick inverter data updates
43-
PREDBAT_MAX_CARS = 4 # Matches PK_MAX_CARS in prediction_kernel.cpp and the car_charging_rate_0..3 config items - the hard ceiling on num_cars
43+
PREDBAT_MAX_CARS = 8 # Matches PK_MAX_CARS in prediction_kernel.cpp and the car_charging_rate/_1../_7 config items - the hard ceiling on num_cars
4444

4545
# 240v x 100 amps x 3 phases / 1000 to kW / 60 minutes in an hour is the maximum kWh in a 1 minute period
4646
MAX_INCREMENT = 240 * 100 * 3 / 1000 / 60

apps/predbat/prediction_kernel.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
#include <vector>
2828

2929
#define PK_ABI_VERSION 3
30-
#define PK_PARITY_REVISION 5
31-
#define PK_MAX_CARS 4
30+
#define PK_PARITY_REVISION 6
31+
#define PK_MAX_CARS 8
3232
#define PK_RUN_EVERY 5 // const.py RUN_EVERY
3333

3434
namespace {

apps/predbat/prediction_kernel.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
# Expected ABI/parity revisions of the shared library (see prediction_kernel.cpp)
3434
KERNEL_ABI_VERSION = 3
35-
KERNEL_PARITY_REVISION = 5
35+
KERNEL_PARITY_REVISION = 6
3636

3737
# Maximum number of cars supported by the kernel (PK_MAX_CARS in prediction_kernel.cpp)
3838
KERNEL_MAX_CARS = PREDBAT_MAX_CARS
@@ -94,8 +94,8 @@ class PkContext(ctypes.Structure):
9494
("export_today_now", ctypes.c_double),
9595
("iboost_today", ctypes.c_double),
9696
("car_charging_loss", ctypes.c_double),
97-
("car_charging_limit", ctypes.c_double * 4),
98-
("car_charging_soc", ctypes.c_double * 4),
97+
("car_charging_limit", ctypes.c_double * KERNEL_MAX_CARS),
98+
("car_charging_soc", ctypes.c_double * KERNEL_MAX_CARS),
9999
("iboost_max_energy", ctypes.c_double),
100100
("iboost_max_power", ctypes.c_double),
101101
("iboost_min_power", ctypes.c_double),
@@ -166,7 +166,7 @@ class PkResult(ctypes.Structure):
166166
("metric_keep", ctypes.c_double),
167167
("final_iboost", ctypes.c_double),
168168
("final_carbon_g", ctypes.c_double),
169-
("car_soc_next", ctypes.c_double * 4),
169+
("car_soc_next", ctypes.c_double * KERNEL_MAX_CARS),
170170
("iboost_next", ctypes.c_double),
171171
("soc_min_minute", ctypes.c_int32),
172172
("car_soc_next_valid", ctypes.c_int32),
32 Bytes
Binary file not shown.
176 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
116 Bytes
Binary file not shown.
80 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)