Setup Insteon hidden door sensor

Posted on
Sun Feb 23, 2020 11:37 pm
dduff617 offline
Posts: 659
Joined: Jul 05, 2006
Location: Massachusetts, USA

Setup Insteon hidden door sensor

I found at one point that I had instances of Insteon door sensors purchased at different times with widely varying battery usage. Scanning logs, I found big variation in the time between sending heartbeat messages. A bit more investigation turned up differences in other parameter settings as well. I wanted a way to set my devices for consistency and max battery life.

Code: Select all
# Set parameters for hidden motion sensors, including heartbeat interval and LED mode.
# This script is useful to set up Insteon Hidden Motion Sensor (2845-222).   
#
# author: D. Duff user dduff617 on forums.indigodomo.com (duff@alum.mit.edu)
#
# Why? 
# a) Indigo doesn't currently provide any UI for accessing these settings.
# b) Prolong battery life.
# c) Cut down unnecessary Insteon traffic
#
# What exactly does this do?
# Sets the heartbeat interval.  Value can be set from 5 mins to "about a day".   I use heartbeat
# for battery monitoring and as such, for me there's really no point in setting it to anything
# other than max value to save batteries and reduce network traffic.   
# Turns off LED.  Again this is done primarily to save battery - nothing but a waste of battery 
# having an LED shine when buried inside a hole in my doorframe.
#
# BEFORE RUNNING THIS SCRIPT
# First, set this to the name of the device you want to configure.
d = indigo.devices["FOY-CLOS Door Open"]

# Next, Put device in linking mode by holding the set button (if device is out of the wall)
# If device is installed in the wall, you can put it in linking mode, by executing the following steps:
# 1. push the plunger
# 2. release
# 3. push the plunger
# 4. release
# 5. push the plunger and hold it until device beeps.
# 6. release the plunger.   
# You have to do steps 1-5 in very quick succession.   The beep is not very loud, so you have to listen for it.
# The device stays in linking mode for about a minute.

# set heartbeat interval extended command to door sensor, returns a standard ack.
# note that while heartbeat interval can be set, the results must be observed indirectly
# (as the time delta between successive heartbeats).  Value can not be read directly from
# the device, which is kind of annoying. 
def setHeartbeatInterval (device, value=0) :
   setHeartbeatIntervalCmd = [
      0x2E,
      0x00,
      0x00,   # unused
      0x02,   # set hearbeat interval command
      value   # heartbeat interval value.  0x01->5min, 0x02->10min, 0x03->15min etc.  special 0->"about 24 hrs" (emperically, turns out to be roughly in the range of 19:45 to 21:40)
   ]
   indigo.server.log("Attempting to set heartbeat for device {} to {}".format(device.name, value))
   # setting calcCrc=True here will cause it to fail - why? i don't know.
   reply = indigo.insteon.sendRawExtended(device.address, setHeartbeatIntervalCmd, suppressLogging=True)
   if reply.cmdSuccess :
      # indigo.server.log("reply success: {:d}, ack value: {:#x}".format(reply.cmdSuccess, reply.ackValue))
      indigo.server.log("Heartbeat interval for device {} was successfully set to {} or {}".format(device.name, value, describeSensorHeartbeat(value)))
      return True
   else:
      indigo.server.log("Extended command failed.  Device may be offline?", isError=True)
      return false

def describeSensorHeartbeat(value) :
   if value==0 :
      return "about 24 hours"
   else:
      return "{} minutes".format(5*value)

# read operating flags is a standard (not extended) command.
# should return result in a standard ack (?) with the interesting results packed into a single reply byte.
# note: this does not return the heartbeat interval and afaik, there is no way to do this.
def readOperatingFlags (device):
   # indigo.server.log("Attempting to read operating flags 0 for device {}".format(device.name))
   reply = indigo.insteon.sendRaw(device.address, [0x1f, 0x00], waitUntilAck=True, suppressLogging=True)
   if reply.cmdSuccess:
      # indigo.server.log("reply success: %d, ack value: %02X" % (reply.cmdSuccess, reply.ackValue))
      # indigo.server.log("ReplyBytes: {}".format(reply.replyBytes))
      indigo.server.log("Operating Flags for device {}".format(device.name))
      describeOperatingFlags(reply.ackValue)
   else:
      indigo.server.log("Command failed.  Device may be offline?")

def describeOperatingFlags (reply) :
   # indigo.server.log("calling descibeOperatingFlags with reply {}".format(reply))
   # info from "Developer Notes" for 2845-222 dated October 2013.
   # bit 0 = Do Cleanup Report
   # bit 1 = 2 Groups
   # bit 2 = Repeat Open
   # bit 3 = Repeat Closed
   # bit 4 = Link to FF Group
   # bit 5 = LED Disable
   # bit 6 = N/A
   # bit 7 = Programming Lock
   indigo.server.log("Do Cleanup Report: {}".format((reply & 1<< 0) > 0))
   indigo.server.log("2 Groups: {}".format((reply & 1<<1) > 0))
   indigo.server.log("Repeat Open: {}".format((reply & 1<<2 ) > 0))
   indigo.server.log("Repeat Closed: {}".format((reply & 1>>3) > 0))
   indigo.server.log("Link to FF Group: {}".format((reply & 1<<4) > 0))
   indigo.server.log("LED Disable: {}".format((reply & 1<<5) > 0))
   # indigo.server.log("Unused flag: {}".format((reply & 1<<6) > 0))
   indigo.server.log("Programming Lock: {}".format((reply & 1<<7) > 0))

# set LED Mode.  mode=True means LED is ON.   mode=False means LED is OFF, aka disabled.
def setLEDMode (device, mode=False):
   indigo.server.log("Attempting to set LED Mode for device {} to {}".format(device.name, mode))
   cmdBytes = [0x20, 0x03 if mode else 0x02]
   reply = indigo.insteon.sendRawExtended(device.address, cmdBytes, suppressLogging=True)
   if reply.cmdSuccess:
      #indigo.server.log("Reply success: {:d}, Ack value: {:02X}, ReplyBytes: {}".format(reply.cmdSuccess, reply.ackValue, reply.replyBytes))
      indigo.server.log("LED mode for device {} was successfully set to {}".format(device.name, mode))
      return True
   else:
      indigo.server.log("Command failed.  Device may be offline?", isError=True)
      return False

# simple ping to test that a device is awake.
def awakeCheck (device):
   result = indigo.device.ping(d, suppressLogging=True)
   if result["Success"]:
      indigo.server.log("Device is awake and listening.  %.2f seconds ping for %s" % (result["TimeDelta"]/1000.0, device.name))
      return True
   else:
      indigo.server.log("ping failed for %s" % (d.name), isError=True)
      return False


#
# here's where the action happens:
if (not awakeCheck(d)):
   indigo.server.log("Device is not awake or not in range.  Quitting.", isError=True)
   quit()

# set heartbeat interval (to save batteries)
if (not setHeartbeatInterval(d)):
   indigo.server.log("Set heartbeat interval failed.  Quitting.", isError=True)
   quit()

# turn off LED
if not setLEDMode(d):
   indigo.server.log("Set LED Mode failed.  Quitting.")
   quit()

# dump the current operating flags to logs so we can confirm LED status and other settings.
readOperatingFlags(d)


Posted on
Mon Feb 24, 2020 9:35 am
jay (support) offline
Site Admin
User avatar
Posts: 18200
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Setup Insteon hidden door sensor

Thanks for the contribution!

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 2 guests