Jump to content

Diesel

Members
  • Posts

    52
  • Joined

  • Last visited

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Diesel's Achievements

Member

Member (3/6)

5

Reputation

  1. You'll find many different perspectives on these forums. Such is the variety of life. But there's some basic fundamental covenants to a properly working IoX/Insteon system; 1. Never use manual links between devices unless you enjoy pain. IoX, the main brain of your system, is not aware of them. 2. For Multi-way circuits (3way, 4way, etc) always create a scene, and add all members to the scene as controllers. 3. A device can only be a controller for 1 scene, but a responder to many scenes. 4. When controlling more than 1-2 devices, a scene is considerably more efficient and reliable. 5. Identify a proper naming convention for your devices and scenes, and stick to it. With that out of the way, here's my perspective; I only use programs when I can't achieve what I want from using a scene. From what I gather from your post, you have a multi-way stair case scene with your master and slaves. These devices should be factory reset to remove any manual links, then added in IoX to a StairCase scene. Stair Case1 (this is the master) - controller to Stair Case Stair Case2 (this is a slave) - controller to Stair Case Stair Case (this is the scene) I don't think you'd want to control your daily lights (ie turn on your Daily Lights scene) every time you turn on your staircase lights so there's no point in making it a controller to the Daily Lights scene. Instead use a keypad button as the Daily Lights controller. You can add more than 1 from strategic locations, main floor, entrance, bedroom, etc and control the daily lights from all of them. We also want all devices in a multi-way circuit to remain in sync if they're part of the Daily Lights. To achieve this, Install the Virtual plugin in PG3x and create a virtual switch called Stair Case VS. Add that to the Stair Case scene as a controller. Then add that virtual switch to the Daily Lights scene as a responder. Then when Daily Lights is turned on, your Stair Case lights (and scene) are turned on, and your master and slave are also in sync. Simple, efficient, and no complicated programs needed. Use a program for Daily Lights scene to turn on/off conditionally (time of day or event).
  2. After another espresso or 2....some more thoughts to ensure it doesn't impede anyone using it as a bridge to programs, and actually enhances program functionality in Phase A; Phase A (enhancement) Minimal, philosophy-pure changes that help everyone and don’t alter scope. 1)nodedefs.xml — add sends on the existing Virtual Dimmer + include fast on/off (If Virtual’s “dimmer/generic” already exists, extend that nodeDef; otherwise add a “VLDIM” nodeDef.) <nodeDef id="VLDIM" nls="VLDIM" name="Virtual Dimmer" icon="LightDimmer"> <sts> <st id="ST" editor="percent" uom="51" /> </sts> <!-- What this node can ACCEPT from scenes/programs --> <accepts> <cmd id="DON"><p id="value" editor="percent" /></cmd> <cmd id="DOF"/> <cmd id="BRT"/> <cmd id="DIM"/> <cmd id="DFON"/> <cmd id="DFOF"/> </accepts> <!-- What this node can SEND (for Programs to “Control is … then …”) --> <sends> <cmd id="DON"/> <cmd id="DOF"/> <cmd id="BRT"/> <cmd id="DIM"/> <cmd id="DFON"/> <cmd id="DFOF"/> </sends> <!-- Optional program-only convenience --> <cmds> <cmd id="SETLVL"><p id="value" editor="percent" /></cmd> <cmd id="QUERY"/> </cmds> </nodeDef> If your schema uses cmds only and no explicit <accepts>/<sends>, we still add handlers for DFON/DFOF and ensure controller events fire so Programs can “Control … is Fast On/Off”. 2) Node class — just add DFON/DFOF handlers and emit sends In the existing Virtual Dimmer node: def cmd_DON(self, command): # update ST and fire “DON sent” (so Programs can trigger) self._set_local_level(self._value_from(command, default=100)) self.reportCmd('DON') def cmd_DOF(self, command): self._set_local_level(0) self.reportCmd('DOF') def cmd_BRT(self, command): self._step(+self.step_pct) self.reportCmd('BRT') def cmd_DIM(self, command): self._step(-self.step_pct) self.reportCmd('DIM') # NEW: Fast On/Off (for parity with physical dimmer) def cmd_DFON(self, command): self._set_local_level(100) self.reportCmd('DFON') def cmd_DFOF(self, command): self._set_local_level(0) self.reportCmd('DFOF') # SETLVL remains for programmatic level changes (program use) def cmd_SETLVL(self, command): pct = self._value_from(command, default=100) self._set_local_level(pct) # optional: do not report a scene “send”; this is a program-level op reportCmd('XXX') should be whatever the Virtual server currently uses to raise the “Control is …” events so Programs can key off Tap On / Tap Off / Fast On / Fast Off / Brighten / Dim. Result: Users can now write Programs like: If Control ‘Virtual Dimmer’ is Fast On → Then Set Scene ‘SceneXYZ’ On If Control ‘Virtual Dimmer’ is Brighten → Then Network Resource “SceneBRT” …without the plugin doing any scene logic itself. Phase B (Optional - opt in): one-line “Relay” to a target node (still a bridge) Add a single param to the Virtual Dimmer (e.g., FORWARD_TO_NODE). When set, the node mirrors the exact sent command to that node via IoX REST. This doesn't introduce scene logic; it’s just pass-through. Add two drivers/params for visibility & control (optional): GV0 (string) — the target node address (scene group or device), display only. GV1 (bool) — “momentary” cosmetic reset (return ST to 0 after 0.4s), optional. In each send path (DON/DOF/BRT/DIM/DFON/DFOF): if self.forward_to: # For scenes: DON with an optional level argument is supported by IoX REST. # For devices: DON/DOF/BRT/DIM/DFON/DFOF are passed as-is. self._isy.cmd(self.forward_to, 'DON', level_0_to_255) # only when DON has a % value # or self._isy.cmd(self.forward_to, 'DFON') # etc. This still keeps Virtual squarely in “bridge/relay” land: Program patterns (what users can do with Phase A) Single-scene control (ramp by scene presets): - IF Control ‘Virtual Dimmer’ is switched On → Then Set Scene ‘X’ On - IF Control ‘Virtual Dimmer’ is switched Off → Then Set Scene ‘X’ Off Fast on/off: - IF Control ‘Virtual Dimmer’ is switched Fast On → Then Set Scene ‘X’ On (or 100% via NR) - IF Control ‘Virtual Dimmer’ is switched Fast Off → Then Set Scene ‘X’ Off Brighten/Dim stepping: - IF Control ‘Virtual Dimmer’ is Brighten → Then Network Resource calling /rest/nodes/<scene>/cmd/BRT - IF Control ‘Virtual Dimmer’ is Dim → **Then … /DIM` Set exact level (%): - Use SETLVL to set ST (program semantics), then NR: /rest/nodes/<scene>/cmd/DON/<0–255>. - IoX Programs typically don’t pass a % to a Scene “Set On” natively; NR handles it cleanly.
  3. Hi @sjenkins I really appreciate you for all the effort you've put into enhancing Virtual, and even more-so for being open to discussion. The issue I'm trying to solve is Insteon's inherent disfunction with scenes. Native Insteon scenes were created by Insteon because they're the only reliable way to simultaneously control multiple devices. Unfortunately, IoX considers scenes to be stateless, but not really. If a device is a member of multiple scenes, all of those scenes are considered to be in the same state as that device, even if that scene was never called. A scene doesn't have a "truth indicator" that indicates whether a scene is on or off. So we end up having to create a spaghetti of programs to work around this disfunction. As we move forward with Insteon to work with HomeKit, Matter, and other platforms, this disfunction becomes an even bigger issue. A multi-way circuit is just an example of this disfunction. Insteon's native approach is to add the devices all into a scene to keep them in sync. It works as expected when controlling any of the physical devices, but not within UDM or any other platform unless you control the scene itself. What's missing? A Virtual device to act like the physical device(s) in that scene. In my mind, a virtual device would behave the same as a keypad button that acts as a scene controller. A keypad button always reflects the true state of it's scene. It turns the scene on when turned on, turns it off when turned off, brightens and dims the scene when pressed. That said, I appreciate your thoughtful response and I understand your “bridge, not replace Programs” philosophy. Giving some more thought on how to keep Virtual within that scope, but still achieve what I believe can be a game changer for everyone, I propose; Phase A (bridge-only): Extend the Virtual Dimmer’s accepts/sends set to include DFON/DFOF alongside the existing DON/DOF/BRT/DIM. The node will handle/emit those events so Programs can key off Fast On/Off in addition to Tap/Dim/Brighten. No scene awareness or coordination in the plugin. Phase B (optional, default off): Add a single optional text param FORWARD_TO_NODE. When set, the dimmer simply relays whatever it sends (DON/DOF/BRT/DIM/DFON/DFOF) to that node via IoX REST. It remains a bridge/relay — still no scene membership knowledge or multi-dimmer logic inside the plugin. Users who prefer pure Programs can leave it blank and get the exact behavior you described. This way Virtual stays true to its mission (bridge signals to Programs), while enabling a parity command set with physical dimmers and, optionally, a tiny relay convenience for those who want it. Let me know your thoughts and whether you need me to elaborate further.
  4. # nodes/virtual_dimmer.py import time import requests import udi_interface LOGGER = udi_interface.LOGGER class IsyRest: """Tiny helper to call IoX REST for scene commands.""" def __init__(self, base_url, user, password, verify_ssl=True, timeout=5): self.base = (base_url or '').rstrip('/') self.auth = (user, password) if user else None self.verify = verify_ssl self.timeout = timeout def cmd(self, node_or_scene_addr, command, *args): if not self.base: raise RuntimeError("ISY_BASE_URL not configured") url = f"{self.base}/rest/nodes/{node_or_scene_addr}/cmd/{command}" if args: url += "/" + "/".join(str(a) for a in args) r = requests.get(url, auth=self.auth, verify=self.verify, timeout=self.timeout) r.raise_for_status() return True class VirtualDimmer(udi_interface.Node): """ Virtual Dimmer that: - As a Responder: updates its own ST on DON/DOF/BRT/DIM/etc. - As a Controller: forwards DON/DOF/DFON/DFOF/BRT/DIM/BMAN/SMAN to a native IoX scene (group). """ id = 'VLDIM' # must match nodedefs.xml # Drivers: # ST : 0-100 % level (uom 51) # GV0 : scene/group address this node controls (display) # GV1 : momentary flag 0/1 (if 1, returns to 0% after send) drivers = [ {'driver': 'ST', 'value': 0, 'uom': 51}, {'driver': 'GV0', 'value': 0, 'uom': 56}, {'driver': 'GV1', 'value': 0, 'uom': 2}, ] def __init__(self, polyglot, primary, address, name, isy_rest: IsyRest, scene_addr: str = None, momentary: bool = False, step_pct: int = 3): super().__init__(polyglot, primary, address, name) self.isy = isy_rest self.scene_addr = scene_addr # e.g. 0001, 0012 (group id) self.momentary = 1 if momentary else 0 self.step_pct = max(1, min(20, int(step_pct))) # ---------- lifecycle ---------- def start(self): self.setDriver('GV1', self.momentary, report=True, force=True) if self.scene_addr: try: self.setDriver('GV0', int(self.scene_addr), report=True, force=True) except Exception: # not numeric; ignore—GV0 is display only pass self.reportDrivers() def query(self, command=None): self.reportDrivers() # ---------- helpers ---------- @staticmethod def pct_to_255(pct: int) -> int: pct = max(0, min(100, int(pct))) return round(pct * 255 / 100) def _set_local_level(self, pct: int): pct = max(0, min(100, int(pct))) self.setDriver('ST', pct, report=True, force=True) def _send_scene(self, cmd, *args): if not self.scene_addr: LOGGER.debug(f"{self.address}: no scene_addr configured; skip send {cmd} {args}") return try: self.isy.cmd(self.scene_addr, cmd, *args) except Exception as e: LOGGER.error(f"{self.address}: scene command failed: {cmd} {args} -> {e}") def _momentary_reset(self): if self.momentary: time.sleep(0.4) self._set_local_level(0) # ---------- command handlers ---------- # DON (optionally with level 0-100 from Admin Console) def cmd_DON(self, command): lvl = 100 if command and 'value' in command: try: lvl = int(command.get('value')) except Exception: lvl = 100 self._set_local_level(lvl) # responder behavior self._send_scene('DON', self.pct_to_255(lvl)) # controller behavior self._momentary_reset() def cmd_DOF(self, command): self._set_local_level(0) self._send_scene('DOF') self._momentary_reset() def cmd_DFON(self, command): self._set_local_level(100) self._send_scene('DFON') self._momentary_reset() def cmd_DFOF(self, command): self._set_local_level(0) self._send_scene('DFOF') self._momentary_reset() def cmd_BRT(self, command): new_lvl = min(100, int(self.getDriver('ST')) + self.step_pct) self._set_local_level(new_lvl) self._send_scene('BRT') def cmd_DIM(self, command): new_lvl = max(0, int(self.getDriver('ST')) - self.step_pct) self._set_local_level(new_lvl) self._send_scene('DIM') def cmd_BMAN(self, command): self._send_scene('BMAN') def cmd_SMAN(self, command): self._send_scene('SMAN') # Explicit “Set Level” from programs (0–100) def cmd_SETLVL(self, command): try: pct = int(command.get('value')) except Exception: pct = 100 self._set_local_level(pct) self._send_scene('DON', self.pct_to_255(pct)) self._momentary_reset() commands = { 'DON': cmd_DON, 'DOF': cmd_DOF, 'DFON': cmd_DFON, 'DFOF': cmd_DFOF, 'BRT': cmd_BRT, 'DIM': cmd_DIM, 'BMAN': cmd_BMAN, 'SMAN': cmd_SMAN, 'SETLVL': cmd_SETLVL, 'QUERY': query, }
  5. Thanks for this! Ideally, a Virtual Dimmer would behave the same as a physical dimmer for consistency. Consider a potential common use case of a virtual controller of a multi-way circuit scene.Virtual dimmer controls and keeps the scene, and physical dimmers all in sync. Maybe something along these lines? User action (virtual dimmer) Exact behavior to emulate Commands to send (to scene) Notes Single tap ON(top paddle) Go to scene’s programmed On Levels with scene’s ramp DON (no level parameter) Mirrors what a physical dimmer sends when used as a scene controller. Single tap OFF(bottom paddle) Ramp responders to off per scene link DOF Double-tap ON Fast On (immediate to full) DFON Bypasses ramp to 100%. Double-tap OFF Fast Off (immediate off) DFOF Bypasses ramp. Press & hold ON (top hold) Start brightening until release BMAN (once), then periodic BRT until release, then SMAN Repeat rate ~300–400 ms? Press & hold OFF (bottom hold) Start dimming until release BMAN (once), then periodic DIM until release, then SMAN Same repeat rate. Set Level(slider/command with %) Jump scene to specific runtime level DON/<0–255> Useful for admin UI or programmatic ontrol.
  6. IMHO option 2 makes the most sense for a virtual dimmer, otherwise with option 1 it behaves like a switch. A virtual dimmer should function in the same way as a physical dimmer or a keypad button added as a scene controller. Holding a Dimmer or Keypad button down brightens or dims a scene. Pressing a keypad button turns a scene ON or OFF. One of the most useful applications for a virtual dimmer as a scene controller is for multi-way circuits. Consider a common 3-way lighting circuit where 2 physical dimmer switches are added to a "3way" scene, both as controllers. BUT in IoX if you control any of the 2 dimmers directly, the other isn't in sync and neither is the scene. The virtual dimmer solves this dysfunctional behaviour where everything remains in sync as it should be.
  7. Virtual Dimmer only allows adding as a scene responder. Controller/Responder is greyed out.
  8. @sjenkins Is a virtual dimmer not able to used as a scene controller?
  9. Thanks so much! Loaded beta 3.1.14 into another slot. Created a virtual switch and was able to add it as a scene controller - Awesome! {"id": "10", "type": "switch", "name": "My vs Name"} Device type in AC shows as Virtual Switch Created a virtual dimmer but it only allows the option to add it as a scene responder. {"id": "30", "type": "dimmer", "name": "My vd Name"} Device type in AC shows as Virtual Generic The scene I tried adding it to is a 3-way circuit with 2 dimmers.
  10. @sjenkins There's some really great integrations in the store, but Virtual is one of the most important. Virtual switches/dimmers as scene controller & responder solves so many issues. Thanks so much for taking the time to make this happen! 😊
  11. from polyinterface import Node, LOGGER class VirtualSwitch(Node): """ Virtual Switch Node for PG3x that can act as a controller for a native Insteon scene. """ id = 'virtual_switch' def __init__(self, polyglot, primary, address, name, scene_id=None): super().__init__(polyglot, primary, address, name) self.scene_id = scene_id # Optional: Native Insteon scene this switch controls self.add_driver('ST', 0) # State driver: 0=off, 1=on def start(self): LOGGER.info(f"Starting Virtual Switch '{self.name}' with scene_id={self.scene_id}") # Register command handlers self.poly.on('ON', self.on_command) self.poly.on('OFF', self.off_command) def on_command(self, command=None): """Handle ON command from PG3x or scene activation""" if self.scene_id: self.send_scene_command('ON') self.set_driver('ST', 1) # Update switch state def off_command(self, command=None): """Handle OFF command""" if self.scene_id: self.send_scene_command('OFF') self.set_driver('ST', 0) def send_scene_command(self, cmd): """ Sends the ON/OFF command to the linked Insteon scene via IoX. Replace the below with actual PG3x API call to trigger a scene. """ try: LOGGER.info(f"Sending command '{cmd}' to scene {self.scene_id}") # Example pseudo-call; replace with actual API method # self.poly.iot.send_scene_command(self.scene_id, cmd) except Exception as e: LOGGER.error(f"Failed to send command to scene {self.scene_id}: {e}") def set_scene_id(self, scene_id): """Optional helper to dynamically update the controlled scene""" self.scene_id = scene_id LOGGER.info(f"Virtual Switch '{self.name}' now controls scene {scene_id}")
  12. Hi, @sjenkins thank you so much for the work that's gone into this plugin. Any possibility to enhance it so that virtual switches can be a scene controller rather than only a responder? Taking it a step further, also be able to create a virtual dimmer? It would solve a very fundamental and fatal issue with the way IoX considers a scene state.
  13. Thanks for taking the time to share your detailed experience with the update on Polisy. I was just about to press that upgrade button (in AC) on my Polisy when I read your post. I have no time to resurrect the dead this week so I'm going to wait for Michel to work out the upgrade bugs before I hit that upgrade button.
  14. Hi Lee, Thanks for your help. I've created the variable and related program, and updated the email notif program as you outlined. When trying to rename the variable from Int_1 to something meaningful, it always seems to reset back to Int_1? I'm surprised that there's no simpler (or inherent) way to throttle or limit the number/interval of emails sent when motion is detected? For example: You have a motion sensor in the back yard and want to receive an email notification when there's movement, so you can have a look on your cameras to see what's going on. If the gardner shows up, your inbox gets hammered every second while cuts the grass!
  15. Hi Michel, I just want to receive an email notification as soon as the motion sensor is triggered, but only once and then not again for X minutes, otherwise the notifications flood my inbox. I don't want the system to wait 15mins after sensing motion to notify me. For example, the sensor will detect motion when the Gardner is cutting the grass, but currently I would receive 35 emails a minute. Just once would be fine, and then if motion continues 15 or 30mins later, it can send another notification again. How do I achieve this? Thanks for your help.
×
×
  • Create New...