Skip to content

Commit 99d9084

Browse files
committed
fix: BLE lacks stopAskingToStartCharging
1 parent bf7e852 commit 99d9084

1 file changed

Lines changed: 58 additions & 15 deletions

File tree

lib/TWCManager/Vehicle/TeslaBLE.py

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ def __init__(self, master):
108108
# Retry statistics tracking
109109
self.retry_stats = {}
110110

111+
# Per-VIN flag: True once the car has confirmed it is already in the
112+
# desired charge state (complete, is_charging, disconnected, etc.).
113+
# Prevents re-sending a start command on every poll cycle.
114+
# Reset to False when a stop-charge task arrives.
115+
self._stopAskingToStartCharging = {}
116+
111117
# Persistent D-Bus session daemon shared across all tesla-control calls.
112118
# dbus-launch only spawns a new daemon when DBUS_SESSION_BUS_ADDRESS is
113119
# absent from the environment. By starting one daemon here and passing its
@@ -193,13 +199,24 @@ def car_api_charge(self, task):
193199
logger.error("Task missing required 'charge' key")
194200
return False
195201

202+
# When stopping, reset per-VIN "stop asking" flags so the next
203+
# start cycle starts fresh (mirrors TeslaAPI.car_api_charge).
204+
if not charge:
205+
self._stopAskingToStartCharging.clear()
206+
196207
# If we know the VIN of the vehicle connected to the TWC Slave, we'll send the command
197208
# directly to that vehicle
198209
vin = task.get("vin", None)
199210
if vin:
200211
logger.debug(f"BLE command for specific VIN: {vin}, charge: {charge}")
201212

202213
if charge:
214+
if self._stopAskingToStartCharging.get(vin):
215+
logger.debug(
216+
"BLE: not re-requesting charge start for %s: already in desired state"
217+
% vin
218+
)
219+
return True
203220
if self._scheduleBlocksStart(vin):
204221
logger.info(
205222
f"{vin} is waiting on its in-car charging schedule; not sending BLE start"
@@ -231,6 +248,13 @@ def car_api_charge(self, task):
231248
for vehicle in self.master.settings["Vehicles"].keys():
232249
try:
233250
if charge:
251+
if self._stopAskingToStartCharging.get(vehicle):
252+
logger.debug(
253+
"BLE: not re-requesting charge start for %s: already in desired state"
254+
% vehicle
255+
)
256+
success_count += 1
257+
continue
234258
if self._scheduleBlocksStart(vehicle):
235259
logger.info(
236260
f"{vehicle} is waiting on its in-car charging schedule; not sending BLE start"
@@ -267,6 +291,18 @@ def car_api_charge(self, task):
267291
logger.error(f"BLE car_api_charge failed with exception: {e}")
268292
return False
269293

294+
def _is_already_satisfied(self, output):
295+
"""Return True if output indicates the car is already in the desired charge state."""
296+
if not output:
297+
return False
298+
if isinstance(output, bytes):
299+
output = output.decode("utf-8", errors="ignore")
300+
output_lower = output.lower()
301+
return any(
302+
("car could not execute command: " + reason) in output_lower
303+
for reason in ("complete", "is_charging", "charging", "requested", "disconnected")
304+
)
305+
270306
def parseCommandOutput(self, output):
271307
"""
272308
Enhanced command output parsing with detailed error categorization.
@@ -286,14 +322,21 @@ def parseCommandOutput(self, output):
286322
"Command executed successfully",
287323
"Vehicle responded",
288324
"Success",
289-
# "Already in desired state" responses — car is charging or done; goal achieved
290-
"car could not execute command: complete",
291-
"car could not execute command: is_charging",
292-
"car could not execute command: charging",
293-
"car could not execute command: requested",
294325
]
295326

296-
# Error indicators for detailed logging
327+
output_lower = output.lower()
328+
329+
# Check for success
330+
for indicator in success_indicators:
331+
if indicator.lower() in output_lower:
332+
logger.debug(f"BLE command success: {indicator}")
333+
return True
334+
335+
if self._is_already_satisfied(output):
336+
logger.debug("BLE command success: already in desired state")
337+
return True
338+
339+
# Categorize errors for detailed logging
297340
error_indicators = {
298341
"timeout": ["timeout", "timed out", "no response"],
299342
"connection": ["connection failed", "unable to connect", "bluetooth error"],
@@ -306,15 +349,6 @@ def parseCommandOutput(self, output):
306349
"command_failed": ["command failed", "error executing", "operation failed"],
307350
}
308351

309-
output_lower = output.lower()
310-
311-
# Check for success
312-
for indicator in success_indicators:
313-
if indicator.lower() in output_lower:
314-
logger.debug(f"BLE command success: {indicator}")
315-
return True
316-
317-
# Categorize errors for better debugging
318352
error_type = "unknown"
319353
for category, indicators in error_indicators.items():
320354
for indicator in indicators:
@@ -586,6 +620,15 @@ def startCharging(self, vin):
586620
return False
587621

588622
success = self.parseCommandOutput(ret)
623+
624+
# If the car reported it is already in the desired state, record
625+
# that so car_api_charge won't re-send the command next cycle
626+
# (mirrors TeslaAPI's stopAskingToStartCharging logic).
627+
if success and self._is_already_satisfied(ret):
628+
self._stopAskingToStartCharging[vin] = True
629+
logger.info(
630+
"BLE: %s already in desired charge state; will not re-request" % vin
631+
)
589632
logger.info(
590633
f"Start charging for {vin}: {'success' if success else 'failed'}"
591634
)

0 commit comments

Comments
 (0)