This looks awesome. However, I'm having a few problems getting it to work.
I really like how this plugin probes the GC to discover the module capabilities. Unfortunately, the GC-100 I have is really ancient and its firmware doesn't support a couple of command the plugin makes: get_IR and get_SERIAL. Here is a modified version of gcnet.py's _calldown() method that works with my GC-100, and I believe it should still work fine with newer versions of the firmware (it still calls get_IR and get_SERIAL for newer fw versions):
Code: Select all
def _calldown(self, ctx, data=None):
""" Unified GCNet callback driver. """
if ctx.state is not None:
indigo.server.log("received state: " + str(ctx.state))
if data is not None:
indigo.server.log(" received data: " + str(data))
if ctx.error:
return self.callout(ctx)
if ctx.state == 'error':
if self.type is None: # this one was on purpose
if data == "14":
self.type = "GC-100" # it's a GC-100 of some kind
self._errors = ERRORS_GC_100
self._irqueue = deque() # unified IR queue (one per netdev)
elif data == "001":
self.type = "iTach" # it's an iTach of some kind
self._errors = ERRORS_ITACH
self._irqueue = None # per-device IR queue
self.can_learn = True # supports learning mode
else:
# neither GC-100 nor iTach. Fill in blanks here...
self.callout(Error("Unknown GC-100-like device (returned error %s)" % data))
return
self.command('getversion,0') # get board version
self._probe_count = 0 # start counting devices in flight
self.command('getdevices') # start device enumeration
self._probe_queue = []
else:
# unexpected error. Report it upstream
source = int(data)
self.callout_error(DeviceError(source, self._errors[source]))
elif ctx.state == 'device': # device enumeration ("2,3 IR")
dev, _, r = data.partition(',')
cnt, _, type = r.partition(' ')
if dev == "0": # iTach network device
self.network = type
for addr in range(1, int(cnt)+1):
self._probe_count += 1 # record device probe in flight
self._probe_queue.append((type, dev, addr)) # queue specific probe
elif ctx.state == 'IR': # 2:1,function
addr, type = data.split(',', 1)
if type == "SENSOR" or type == "SENSOR_NOTIFY":
self._create_dev(Sensor, addr, type) # configured for input
elif type == "LED_LIGHTING":
self._create_dev(LEDLight, addr, type) # configured for LED dimmer driving
else:
self._create_dev(IREmitter, addr, type) # configured as IR emitter
elif ctx.state == 'SERIAL': # 2:1,serial parameters
addr, type = data.split(',', 1)
self._create_dev(Serial, addr, type)
elif ctx.state == 'devices done': # device list complete
major, minor = self.version.split('-', 1)
for cmd_tuple in self._probe_queue:
(type, dev, addr) = cmd_tuple
if type == 'RELAY':
self._create_dev(Relay, "%s:%s" % (dev, addr), None)
elif float(major) <= 2.4:
# Really old firmware versions (not sure of exact version, but
# definitely earlier than 2.5) do not support get_SERIAL
# or get_IR commands. For get_SERIAL we have enough information
# to construct from the getdevices enumeration. For get_IR
# we just presume all addresses on the module are set to IR
# emitting and not sensor inputing -- we could make this smarter
# by sending getstate messages (which are supported) and if we
# get back a state reply we know it is a sensor versus an IR
# will return an error 13.
if type == 'SERIAL':
self._create_dev(Serial, "%s:%s" % (dev, addr), None)
elif type == 'IR':
self._create_dev(IREmitter, "%s:%s" % (dev, addr), "IR")
# OR:
# self._create_dev(Sensor, "%s:%s" % (dev, addr), "SENSOR")
#
# OR:
# Could send getstate to determine sensor versus IR, but will require
# some additional ctx.state handling...
#
# time.sleep(PROBE_DELAY) # don't overwhelm the hardware
# self.command("getstate,%s:%d" % (dev, addr)) # issue specific probe
else:
time.sleep(PROBE_DELAY) # don't overwhelm the hardware
self.command("get_%s,%s:%d" % cmd_tuple) # issue specific probe
self._probe_queue = []
elif ctx.state == 'version':
self.version = data # board version
elif ctx.state == 'start learning': # enter learning mode
self._learning = True
self.callout('learning', True)
elif ctx.state == 'stop learning': # exit learning mode
self._learning = False
self.callout('learning', False)
elif ctx.state == 'learned': # IR signal learned
self.callout('learned', self._iTach_learned_event(data))
elif ctx.state == 'reply': # any other reply
(cmd, addr, args) = data.split(',', 2)
if self.devmap and addr in self.devmap:
self.devmap[addr]._calldown(ctx, cmd, args)
else:
self.callout(Error("Unconsumed event", data))
(I can email you the file if you would like)
However, I am still not able to get IR commands sent out consistently. First, here is some logging showing the device activating and becoming available correctly (note I added some additional comm logging):
Code: Select all
Starting plugin "Cynical Caché 0.9.1"
Plugin "Cynical Caché" connected
Plugin "Cynical Caché 0.9.1" started
Cynical Caché mapping device "cyn-gc100" 22857726(gcnet)
Cynical Caché cyn-gc100 starting
Cynical Caché cyn-gc100 connecting to network device 192.168.1.183
Cynical Caché mapping device "cyn-gc100-emitter 5:1" 1298719808(iremitter)
Cynical Caché cyn-gc100-emitter 5:1 starting
Cynical Caché plugin starting asyn operation
Cynical Caché using no IR database
Cynical Caché SENDING: mumblefrotz
Cynical Caché RCVD state: error
Cynical Caché RCVD data: 14
Cynical Caché SENDING: getversion,0
Cynical Caché SENDING: getdevices
Cynical Caché RCVD state: version
Cynical Caché RCVD data: 2.4-12
Cynical Caché RCVD state: device
Cynical Caché RCVD data: 1,1 SERIAL
Cynical Caché RCVD state: device
Cynical Caché RCVD data: 2,1 SERIAL
Cynical Caché RCVD state: device
Cynical Caché RCVD data: 3,3 RELAY
Cynical Caché RCVD state: device
Cynical Caché RCVD data: 4,3 IR
Cynical Caché RCVD state: device
Cynical Caché RCVD data: 5,3 IR
Cynical Caché RCVD state: devices done
Cynical Caché RCVD data:
Cynical Caché cyn-gc100 ready with 11 device(s)
Cynical Caché cyn-gc100-emitter 5:1 host device cyn-gc100 now available
Cynical Caché cyn-gc100-emitter 5:1 is now ready
I then set up an action to Send IR Signal "<NEC:74b2/2E>". When executed I think it works the first time, but subsequent requests fail. It looks like the "completeir" response is losing the 'c'? Note the device state queue count is stuck above 0.
Code: Select all
Action Group cyn-gc100 IR blast
Cynical Caché send <NEC:74b2/2f> to <irdev.IREmitter object at 0x2f96ef0> repeating 0
Cynical Caché sending sendir,5:1,2,38000,1,1,342,170,22,21,22,63,22,21,22,21,22,63,...,22,63,23,2200
Cynical Caché received state: reply
Cynical Caché received data: ompleteir,5:1,2
Action Group cyn-gc100 IR blast
Cynical Caché send <NEC:74b2/2f> to <irdev.IREmitter object at 0x2f96ef0> repeating 0
Action Group cyn-gc100 IR blast
Cynical Caché send <NEC:74b2/2f> to <irdev.IREmitter object at 0x2f96ef0> repeating 0
Action Group cyn-gc100 IR blast
Cynical Caché send <NEC:74b2/2f> to <irdev.IREmitter object at 0x2f96ef0> repeating 0
Action Group cyn-gc100 IR blast
Cynical Caché send <NEC:74b2/2f> to <irdev.IREmitter object at 0x2f96ef0> repeating 0
If I telnet to my GC-100 and copy/paste the exact above sendir command, it works correctly (I see a full completeir reply):
Code: Select all
sendir,5:1,2,38000,1,1,342,170,22,21,22,63,22,21,22,21,22,63,22,...,22,63,23,2200
completeir,5:1,2
Next, note that I'm seeing it get into a bad state. This might be related to the failure above. Sometimes when I request the same action above (or the clearIR action) I get these:
Code: Select all
Action Group cyn-gc100 IR blast
Cynical Caché Error ignoring sendIR for unready device cyn-gc100-emitter 5:1
Action Group cyn-gc100 IR blast
Cynical Caché Error ignoring sendIR for unready device cyn-gc100-emitter 5:1
Action Group cyn-gc100 IR clear
Cynical Caché Error ignoring clearIR for unready device cyn-gc100-emitter 5:1
Action Group cyn-gc100 IR clear
Cynical Caché Error ignoring clearIR for unready device cyn-gc100-emitter 5:1
Action Group cyn-gc100 IR clear
Cynical Caché Error ignoring clearIR for unready device cyn-gc100-emitter 5:1
Starting and stopping the plugin, or enable/disabling the devices doesn't help. Instead I have to go into the Send IR action and edit the IR string. Strange.