boneIO 1.2.0.dev23__py3-none-any.whl → 1.2.0.dev25__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -265,6 +265,10 @@ class BaseCover(BaseCoverABC, BasicMqtt):
265
265
  _LOGGER.debug("Toggle cover %s from input.", self._id)
266
266
  if self._current_operation != IDLE:
267
267
  await self.stop()
268
+ elif self._position >= 100:
269
+ await self.close()
270
+ elif self._position <= 0:
271
+ await self.open()
268
272
  elif self._last_operation == CLOSING:
269
273
  await self.open()
270
274
  else:
@@ -303,6 +307,10 @@ class BaseCover(BaseCoverABC, BasicMqtt):
303
307
  await self.stop()
304
308
  elif self._position <= always_open_till:
305
309
  await self.open()
310
+ elif self._position >= 100:
311
+ await self.close()
312
+ elif self._position <= 0:
313
+ await self.open()
306
314
  elif self._last_operation == CLOSING:
307
315
  await self.open()
308
316
  else:
boneio/const.py CHANGED
@@ -187,6 +187,33 @@ cover_actions = {
187
187
  'TILT_CLOSE': 'tilt_close',
188
188
  }
189
189
 
190
+ # Map of cover action method name -> accepted extra_data keys.
191
+ # Actions not listed here (open, close, toggle, stop, etc.) accept no extra params.
192
+ _COVER_ACTION_PARAMS: dict[str, set[str]] = {
193
+ "smart_toggle": {"always_open_till"},
194
+ "set_cover_position": {"position"},
195
+ "set_tilt": {"tilt_position"},
196
+ "set_cover_tilt_position": {"tilt_position"},
197
+ }
198
+
199
+
200
+ def filter_cover_extra_data(action_name: str, extra_data: dict) -> dict:
201
+ """Filter extra_data to only include params accepted by the cover action.
202
+
203
+ Args:
204
+ action_name: The cover method name (e.g. 'open', 'toggle', 'smart_toggle')
205
+ extra_data: Raw extra_data dict from action config
206
+
207
+ Returns:
208
+ Filtered dict with only accepted params for the action.
209
+ """
210
+ if not extra_data:
211
+ return {}
212
+ allowed = _COVER_ACTION_PARAMS.get(action_name)
213
+ if allowed is None:
214
+ return {}
215
+ return {k: v for k, v in extra_data.items() if k in allowed}
216
+
190
217
  INA219 = "ina219"
191
218
  VIRTUAL_ENERGY_SENSOR = "virtual_energy_sensor"
192
219
  PINS = {
@@ -13,7 +13,7 @@ import json
13
13
  import logging
14
14
  from typing import TYPE_CHECKING, Any
15
15
 
16
- from boneio.const import COVER, DEVICE_CLASS, ID, NAME, RESTORE_STATE, SHOW_HA, cover_actions
16
+ from boneio.const import COVER, DEVICE_CLASS, ID, NAME, RESTORE_STATE, SHOW_HA, cover_actions, filter_cover_extra_data
17
17
  from boneio.core.utils import TimePeriod, strip_accents
18
18
  from boneio.exceptions import CoverConfigurationException
19
19
  from boneio.integration import ha_cover_availabilty_message
@@ -387,8 +387,10 @@ class CoverManager:
387
387
 
388
388
  try:
389
389
  _f = getattr(cover, action_to_execute)
390
- if extra_data:
391
- await _f(**extra_data)
390
+ # Filter extra_data to only pass params accepted by the action
391
+ filtered = filter_cover_extra_data(action_to_execute, extra_data or {})
392
+ if filtered:
393
+ await _f(**filtered)
392
394
  else:
393
395
  await _f()
394
396
  except Exception as err:
@@ -28,6 +28,7 @@ from boneio.const import (
28
28
  STATE,
29
29
  TOGGLE,
30
30
  cover_actions,
31
+ filter_cover_extra_data,
31
32
  output_actions,
32
33
  )
33
34
  from boneio.core.config import ConfigHelper
@@ -669,6 +670,8 @@ class Manager:
669
670
  continue
670
671
  action_to_execute = action_definition.get("action_to_execute")
671
672
  extra_data = action_definition.get("extra_data", {})
673
+ # Filter extra_data to only pass params accepted by each action
674
+ filtered_data = filter_cover_extra_data(action_to_execute, extra_data)
672
675
  _LOGGER.debug(
673
676
  "Executing action %s for cover %s. Duration: %s",
674
677
  action_to_execute,
@@ -676,7 +679,7 @@ class Manager:
676
679
  time.time() - start_time,
677
680
  )
678
681
  _f = getattr(cover, action_to_execute)
679
- await _f(**extra_data)
682
+ await _f(**filtered_data)
680
683
 
681
684
  elif action == OUTPUT_OVER_MQTT:
682
685
  boneio_id = action_definition.get("boneio_id")
@@ -587,6 +587,7 @@ class RemoteDeviceManager:
587
587
  return await device.control_cover(
588
588
  cover_id=cover_id,
589
589
  action=action,
590
+ **kwargs,
590
591
  )
591
592
 
592
593
  # For MQTT devices, use standard control_cover
@@ -364,7 +364,10 @@ class ESPHomeRemoteDevice(RemoteDevice):
364
364
  "current_operation": current_op,
365
365
  "last_known_operation": last_op,
366
366
  }
367
- _LOGGER.debug("Cover '%s' position: %.2f", cover_id, state.position)
367
+ _LOGGER.debug(
368
+ "Cover '%s' state update: position=%.2f, current_op=%s, last_op=%s",
369
+ cover_id, state.position, current_op, last_op,
370
+ )
368
371
  break
369
372
  except Exception as e:
370
373
  _LOGGER.debug("Error processing state change: %s", e)
@@ -854,27 +857,52 @@ class ESPHomeRemoteDevice(RemoteDevice):
854
857
  self._client.cover_command(cover_key, position=0.0)
855
858
  elif action_upper == "STOP":
856
859
  self._client.cover_command(cover_key, stop=True)
857
- elif action_upper == "TOGGLE":
858
- # Toggle based on current operation or last known operation
860
+ elif action_upper in ("TOGGLE", "SMART_TOGGLE"):
861
+ # Toggle based on current operation, position, or last known operation
859
862
  state = self._cover_states.get(cover_id, {})
860
863
  current_op = state.get("current_operation", 0) # 0=IDLE, 1=OPENING, 2=CLOSING
861
864
  last_op = state.get("last_known_operation", 2)
862
865
  cover_pos = state.get("position")
866
+ always_open_till = kwargs.get("always_open_till", 50) if action_upper == "SMART_TOGGLE" else None
863
867
  _LOGGER.debug(
864
- "TOGGLE cover '%s': key=%s, state=%s, current_op=%s, last_op=%s, position=%s, all_states=%s",
865
- cover_id, cover_key, state, current_op, last_op, cover_pos,
866
- {k: v for k, v in self._cover_states.items()},
868
+ "ESPHome %s cover '%s': current_op=%s, last_op=%s, position=%s, always_open_till=%s",
869
+ action_upper, cover_id, current_op, last_op, cover_pos, always_open_till,
867
870
  )
868
871
 
869
872
  if current_op != 0: # If moving, stop it
870
- _LOGGER.debug("TOGGLE -> STOP (cover is moving, current_op=%s)", current_op)
873
+ _LOGGER.debug("%s -> STOP (cover is moving, current_op=%s)", action_upper, current_op)
871
874
  self._client.cover_command(cover_key, stop=True)
872
- elif last_op == 2: # If last operation was CLOSING, open it
873
- _LOGGER.debug("TOGGLE -> OPEN (last_op=CLOSING)")
874
- self._client.cover_command(cover_key, position=1.0)
875
- else: # Otherwise close it
876
- _LOGGER.debug("TOGGLE -> CLOSE (last_op=%s)", last_op)
877
- self._client.cover_command(cover_key, position=0.0)
875
+ elif cover_pos is not None:
876
+ # Position is known — use it for smarter decisions
877
+ pos_pct = int(cover_pos * 100)
878
+ if always_open_till is not None and pos_pct <= always_open_till:
879
+ # SMART_TOGGLE: below threshold → always open
880
+ _LOGGER.debug("SMART_TOGGLE -> OPEN (pos=%d%% <= threshold=%d%%)", pos_pct, always_open_till)
881
+ self._client.cover_command(cover_key, position=1.0)
882
+ elif cover_pos >= 0.99:
883
+ # Fully open → close
884
+ _LOGGER.debug("%s -> CLOSE (fully open, pos=%.2f)", action_upper, cover_pos)
885
+ self._client.cover_command(cover_key, position=0.0)
886
+ elif cover_pos <= 0.01:
887
+ # Fully closed → open
888
+ _LOGGER.debug("%s -> OPEN (fully closed, pos=%.2f)", action_upper, cover_pos)
889
+ self._client.cover_command(cover_key, position=1.0)
890
+ elif last_op == 2:
891
+ # Last was closing → open
892
+ _LOGGER.debug("%s -> OPEN (last_op=CLOSING)", action_upper)
893
+ self._client.cover_command(cover_key, position=1.0)
894
+ else:
895
+ # Last was opening → close
896
+ _LOGGER.debug("%s -> CLOSE (last_op=%s)", action_upper, last_op)
897
+ self._client.cover_command(cover_key, position=0.0)
898
+ else:
899
+ # No position known — use last_op only
900
+ if last_op == 2:
901
+ _LOGGER.debug("%s -> OPEN (no position, last_op=CLOSING)", action_upper)
902
+ self._client.cover_command(cover_key, position=1.0)
903
+ else:
904
+ _LOGGER.debug("%s -> CLOSE (no position, last_op=%s)", action_upper, last_op)
905
+ self._client.cover_command(cover_key, position=0.0)
878
906
  elif action_upper == "TOGGLE_OPEN":
879
907
  state = self._cover_states.get(cover_id, {})
880
908
  current_op = state.get("current_operation", 0)
boneio/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # flake8: noqa
2
- __version__ = "1.2.0dev23"
2
+ __version__ = "1.2.0dev25"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boneio
3
- Version: 1.2.0.dev23
3
+ Version: 1.2.0.dev25
4
4
  Summary: Python App for BoneIO
5
5
  Author-email: Paweł Szafer <pszafer@gmail.com>
6
6
  License: GNU General Public License v3.0
@@ -1,9 +1,9 @@
1
1
  boneio/__init__.py,sha256=Lru1q30NeF7kcGS9XQNMseoVX3Rr2MGmAFHBE5E-bEI,174
2
2
  boneio/bonecli.py,sha256=7T5UAeiH65BUiPQXWLT5LrKcYL2apV3asvAFieHx2fg,10054
3
- boneio/const.py,sha256=5PuhJyhA8ufWj_U2hvlQCmJlFfTn1kap1yMVvqJwZ_M,6134
3
+ boneio/const.py,sha256=703TSqvrACoftJdukAHAQFSENFS6F3i9d2T-bVasHPQ,7089
4
4
  boneio/exceptions.py,sha256=cBph-TsLF7FSz6p4wYeMs3pjVmVRaNQRJP82JgYYV-c,810
5
5
  boneio/runner.py,sha256=0SmyRqss0B7qJqglzt8lauuuB_Cv29rnB-pRQZ37dBk,12476
6
- boneio/version.py,sha256=3Pz8zAfxlbuE6_VQOvYDMiNWHKKn_-23XoJXdKfXeZs,42
6
+ boneio/version.py,sha256=pbxLfl4OE6rc2VupmHc3fxPz3xsSnQRqYIup-ybNrT0,42
7
7
  boneio/boards/0.2/input.yaml,sha256=3HA3rBG23frhZWDcNu76U-Hz5r_uG6WvSsGnXkNE4nE,1581
8
8
  boneio/boards/0.2/output_24_16.yaml,sha256=GQGM3gUK7UobdGL-Ejt9UKdCs1HLPgZ7kziVZ1tjQlA,1462
9
9
  boneio/boards/0.2/output_32_10.yaml,sha256=169ubuzRqFLGiOr7zgB1xL1tKdQyOx2FJZvTCkxCA4U,1920
@@ -44,7 +44,7 @@ boneio/boards/0.8/output_cover.yaml,sha256=UW430upxrzznsowQ2naHxpmfE-rpz_Dxiyq7T
44
44
  boneio/boards/0.8/output_cover_mix.yaml,sha256=3XnGY2hzD7cGhcg6k3G4RCMXrvL09CgeJ1ImdqOIdRM,2656
45
45
  boneio/components/__init__.py,sha256=tdQjs22qE6-hlNE1vT4V2xEEHJjJIzlbfQwK2cuJbMo,33
46
46
  boneio/components/cover/__init__.py,sha256=g0sgP_x8pMW6YiuDY0h7jqmrO7-AP1UiVCRSHu0Ih0M,143
47
- boneio/components/cover/cover.py,sha256=k8tnlJAsEMZ61LepmseCtixPF6OIqxS9bJ-ZZbqfZ84,11150
47
+ boneio/components/cover/cover.py,sha256=jB_EmzbFUJWZQrDquJ5DpCvrGiTL_fR7GqJPCrWStHU,11412
48
48
  boneio/components/cover/time_based.py,sha256=uwCYGFZh_00GfFfUv5eNQBtbTX-hGaVZJfwLDEpsQUY,5864
49
49
  boneio/components/cover/venetian.py,sha256=-anHgL51Lar11OQhhCCaIQfk6C2Fm-MG6LSli4Xou1o,13053
50
50
  boneio/components/group/__init__.py,sha256=X4HnybJVvguhKt81qeQSzSeSiUTsTDieSfxIOGCaERc,87
@@ -85,13 +85,13 @@ boneio/core/config/migrations/v2_transition.py,sha256=X-3kPn9y7eJtUlcK1eMTDwQVJA
85
85
  boneio/core/events/__init__.py,sha256=8jUQZitD9wyVr877acMuMNwOC4Wg7qIdtmL4RSzhyTQ,249
86
86
  boneio/core/events/bus.py,sha256=6AwQyFvwjyD1PGxvQ5eEiOGlaCw3mlmKzxMdJ4XLkPU,17391
87
87
  boneio/core/manager/__init__.py,sha256=Vp6LqoIoQnHrGlZRRTNb1VVuzp7Y6VWsor1FmoVjL6k,1071
88
- boneio/core/manager/covers.py,sha256=-WM8miMLF2Qgfm77u5gSo61G-0aQaDcFrCreoX6j750,18621
88
+ boneio/core/manager/covers.py,sha256=UZ8M_tr3gqsC2N35O2flI09P7aYRjS6PC7BlFdSMiFk,18801
89
89
  boneio/core/manager/display.py,sha256=qXOHMbSer62Br3HdQGHC8G1VJBa5mwSpI8RmKSCF4dM,9237
90
90
  boneio/core/manager/inputs.py,sha256=vOOY5G_vl5MM9ZVspeIzAt4mSROHwi3OfB8HFJU_944,37306
91
- boneio/core/manager/manager.py,sha256=YE5RiXjdWEdaibsHGgxt1IDBULWrATEpzR9nWNXhCtA,49531
91
+ boneio/core/manager/manager.py,sha256=eV7jejrVlVGgnmzg9grf1yEY3lHIu6DrAux12B9XCuQ,49730
92
92
  boneio/core/manager/modbus.py,sha256=Pn96F4uXBL0UMAcqM21C7NK6hR9J8soW0quJFdPSfZQ,15788
93
93
  boneio/core/manager/outputs.py,sha256=Ao7qX6lR67IidxeVwjibNflaET_pnK2OGGBm_VMRTXI,33839
94
- boneio/core/manager/remote.py,sha256=1AihcJUuCWLuYc2ZStzd4QgARXdBxyQOWreHKfkqPHk,38376
94
+ boneio/core/manager/remote.py,sha256=HS6WZXepQ6Iwh3Sar_n_6ABXmtzvUwa2Dg3rcJnciT0,38402
95
95
  boneio/core/manager/sensors.py,sha256=MRVJU4rRtsBqDslmQvOgMQleTMvOkD3dYKQRscZNgME,47494
96
96
  boneio/core/manager/templates.py,sha256=QUzi3irFXFXssycyaysDBzqMHfbx9cuD0PtIzybhHC8,30748
97
97
  boneio/core/manager/update.py,sha256=vsOZNHY8gULmEwG14IgjXKXZsYG1DMzpDM7YML5PFq4,25004
@@ -107,7 +107,7 @@ boneio/core/messaging/mqtt.py,sha256=zSQGGGIj7h5bmJ9zD5Svq5LDusRdtvOY6PJzULeXnbA
107
107
  boneio/core/messaging/queue.py,sha256=bZvGAQhMLAInaU5G67cpmbdIEjgn8MGmU5B1MlaPY2A,2395
108
108
  boneio/core/remote/__init__.py,sha256=BcVoQXS4iAjkSHI4l3NTEBweIpIh1rvcu43APW-Y1Oo,1048
109
109
  boneio/core/remote/base.py,sha256=aX1WWEiQSBUd8qV9G5W21Uzs_2EUdfNP-jPOn77M2dY,5544
110
- boneio/core/remote/esphome.py,sha256=J40_zEuvfanR38ZBASH9t8Zn-ISpuevv34Z8iZqod1s,43662
110
+ boneio/core/remote/esphome.py,sha256=e6u28vNnj6wAuseqrUQws8SrJ_r3Kmo4_2dxlv3L4Y4,45539
111
111
  boneio/core/remote/mqtt.py,sha256=B5H_3bpBZtAYIXcIbyN846CmCzJX1Q2MNQBEsZZJJXU,7472
112
112
  boneio/core/remote/wled.py,sha256=rEDkHDejbJwFKwpgQIwWSXK9ceotx2mhNWxuKjgWUjk,19190
113
113
  boneio/core/sensor/__init__.py,sha256=pAcSvGsufNAT5Jy79bC4Ncqo420EjtdZSYrUwSB5yCY,274
@@ -430,9 +430,9 @@ boneio/webui/schema/virtual_energy_sensor.schema.json,sha256=BN6Egh-CAnXSa80bQ6Y
430
430
  boneio/webui/schema/web.schema.json,sha256=cactLq1MVwDL5hu8bLeuq5yiz49BWVS4OtjWLmhbw2M,2592
431
431
  boneio/webui/services/__init__.py,sha256=do_t59tE9zi1qNKkbkq6Et-gc5et4iKyYMntnQBXVG8,282
432
432
  boneio/webui/services/logs.py,sha256=ampdsOx_xwOr0gRC-fW65c1y5Po0nACgUw0tG2bdqUM,11426
433
- boneio-1.2.0.dev23.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
434
- boneio-1.2.0.dev23.dist-info/METADATA,sha256=f1Lucr9Iqqo49W7p6v4StTaGzp5xMRGXJXhvrEx0eeU,1924
435
- boneio-1.2.0.dev23.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
436
- boneio-1.2.0.dev23.dist-info/entry_points.txt,sha256=JX7gluDIkQ6MBlzzxGHMItnBjciiJ73tsXwYcazMW_U,47
437
- boneio-1.2.0.dev23.dist-info/top_level.txt,sha256=ag9S5n1_KXZfyk9tN8R0YUDYbdA--e5a2w2FOD_yMdg,7
438
- boneio-1.2.0.dev23.dist-info/RECORD,,
433
+ boneio-1.2.0.dev25.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
434
+ boneio-1.2.0.dev25.dist-info/METADATA,sha256=WgIzYieCGRXlsW5xrNW2LUrZ6jaivJWlzipgw7QELhk,1924
435
+ boneio-1.2.0.dev25.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
436
+ boneio-1.2.0.dev25.dist-info/entry_points.txt,sha256=JX7gluDIkQ6MBlzzxGHMItnBjciiJ73tsXwYcazMW_U,47
437
+ boneio-1.2.0.dev25.dist-info/top_level.txt,sha256=ag9S5n1_KXZfyk9tN8R0YUDYbdA--e5a2w2FOD_yMdg,7
438
+ boneio-1.2.0.dev25.dist-info/RECORD,,