def main(argv=None): # IGNORE:C0111 '''Command line options.''' if argv is None: argv = sys.argv else: sys.argv.extend(argv) program_name = os.path.basename(sys.argv[0]) program_version = "v%s" % __version__ program_build_date = str(__updated__) program_version_message = '%%(prog)s %s (%s)' % ( program_version, program_build_date) program_shortdesc = __import__('__main__').__doc__.split("\n")[1] program_license = '''%s Created by user_name on %s. Copyright 2016 organization_name. All rights reserved. Licensed under the Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0 Distributed on an "AS IS" basis without warranties or conditions of any kind, either express or implied. USAGE ''' % (program_shortdesc, str(__date__)) try: # Setup argument parser parser = ap.ArgumentParser( description=program_license, formatter_class=ap.RawDescriptionHelpFormatter) parser.add_argument("-c", "--conf", dest="conf", action=ActionConf) parser.add_argument("-b", "--broadcast", dest="broadcast") parser.add_argument("-m", "--mqtt-host", dest="mqtt_host", type=valid_host) parser.add_argument("-k", "--mqtt-port", dest="mqtt_port", type=valid_port) parser.add_argument("-f", "--prime-host", dest="prime_host", type=valid_host) parser.add_argument("-y", "--prime-port", dest="prime_port", type=valid_port) parser.add_argument("-w", "--prime-port2", dest="prime_port2", type=valid_port) parser.add_argument("-q", "--prime-code", dest="prime_code", type=valid_code) parser.add_argument("-z", "--prime-pass", dest="prime_pass") parser.add_argument("-p", "--port", dest="port", type=valid_port) parser.add_argument("-s", "--tcpport", dest="tcpport", type=valid_port) parser.add_argument("-g", "--httpport", dest="httpport", type=valid_port) parser.add_argument("-t", "--timeout", dest="timeout", type=valid_timeout) parser.add_argument("-j", "--emitdelay", dest="emit_delay", type=valid_delay) parser.add_argument("-r", "--retry", dest="retry", type=valid_retry) parser.add_argument("-a", "--action", dest="actions", nargs='+', action=ActionAction) parser.add_argument('-x', '--active_on_finish', action='store_true', dest="active_on_finish") parser.add_argument('-V', '--version', action='version', version=program_version_message) parser.add_argument('-d', '--debug', action='store_true', dest="debug") parser.add_argument( '-e', '--remote', action='store_true', dest="remote") parser.set_defaults(conf=os.path.join(os.getcwd(), 'devices.xml'), devices={}, mqtt_host='', mqtt_port=1883, emit_delay=0, port=10000, tcpport=2802, httpport=2803, actions=[], broadcast='255.255.255.255', active_on_finish=False, timeout=1, retry=3, debug=False, remote=False, prime_host='', prime_port=80, prime_port2=6004, prime_code='', prime_pass='' ) def connect_devices(devices): for _, dv in devices.copy().items(): dv.connect_devices(devices) def add_discovered_devices(action, devices, mqtt_client, mqtt_userdata, emit_delay, **kwargs): for _, v in action.hosts.copy().items(): # _LOGGER.info("current "+k+" nm "+v.name+" lndv "+str(len(devices))) already_saved_device = None # _LOGGER.info("Confronto "+v.name) for _, dv in devices.copy().items(): # _LOGGER.info("VS "+v.name+'/'+dv.name) if v.mac == dv.mac: already_saved_device = dv break # elif v.name==dv.name: # _LOGGER.info("Are you sure? "+v.name+"->"+v.mac.encode('hex')+"/"+dv.mac.encode('hex')) if already_saved_device is None: # _LOGGER.info("changed "+str(v)) devices.update({v.name: v}) action.m_device = True else: already_saved_device.on_stop() v.copy_extra_from(already_saved_device) v.name = already_saved_device.name if isinstance(v, IrManager): v.set_emit_delay(emit_delay) devices.update({already_saved_device.name: v}) if mqtt_client and mqtt_client.is_connected(): v.mqtt_start(mqtt_client, mqtt_userdata) connect_devices(devices) def save_modified_devices(save_filename, save_devices, debug, device, action, **kwargs): # _LOGGER.info("lensv "+str(len(save_devices))) save = True if isinstance(action, ActionDiscovery): save = debug or action.modifies_device() elif isinstance(action, ActionViewtable): save = False if isinstance(action, ActionViewtable1): save = debug elif isinstance(action, ActionViewtable4): dn = device.default_name() if dn in save_devices and dn != device.name: del save_devices[dn] save_devices[device.name] = device save = True else: save = debug elif isinstance(device, DeviceS20): save = debug elif isinstance(device, IrManager): save = debug or action.modifies_device() elif isinstance(action, ActionStatechange) or isinstance(action, ActionSubscribe): save = debug if save: Device.save(save_devices, save_filename, (DEVICE_SAVE_FLAG_MAIN | DEVICE_SAVE_FLAG_TABLE) if debug else DEVICE_SAVE_FLAG_MAIN) def terminate_on_finish(actionexec, force=False, **kwargs): if force or actionexec.action_list_len() <= 1: _LOGGER.info("Terminating...") global term_called term_called = True def do_timer_action(device, timerobj, actionexec, **kwargs): act = ActionEmitir(device, *tuple(timerobj['action'].split(' '))) actionexec.insert_action(act) def insert_arrived_action(cmdline, action, devices, actionexec, pos=-1, **kwargs): if action is None: spl = shlex.split(cmdline) if len(spl) > 1: action = ActionAction.create_action(spl[1:], devices) randid = -1 if action is not None: randid = int(spl[0]) action.set_randomid(randid) EventManager.fire( eventname='ActionParsed', randid=randid, action=action) actionexec.insert_action(action, pos) else: actionexec.insert_action(action, pos) def handle_device_dl(action, devices, **kwargs): if action is not None: action.set_devices(devices) def process_state_change(hp, newstate, devices, mac, actionexec, **kwargs): _LOGGER.info(f'ExtStateChange {mac}') for _, dv in devices.items(): if mac == dv.mac: act = ActionNotifystate(dv, newstate) actionexec.insert_action(act, 1) def mqtt_subscribe(client, userdata, who, lsttopics): if userdata and userdata.mqtt_mid is not None: if isinstance(who, str): log = key = who else: key = str(id(who)) log = who.name _, mid = client.subscribe(lsttopics) userdata.mqtt_mid[key] = mid _LOGGER.info(f"Asked for subscription for {log} with mid {mid}") def mqtt_on_connect(client, userdata, flags, rc): if userdata.mqtt_mid is None and not rc: _LOGGER.info("__main__ connect") userdata.mqtt_mid = dict() mqtt_subscribe(client, userdata, "__main__", [("cmnd/#", 0,)]) for _, d in userdata.devices.items(): d.mqtt_start(client, userdata) else: _LOGGER.info(f"Ignoring connack rc {rc}") def mqtt_on_subscribe(client, userdata, mid, granted_qos): if userdata and userdata.mqtt_mid is not None: log = 'N/A' if "__main__" in userdata.mqtt_mid and userdata.mqtt_mid["__main__"] == mid: userdata.mqtt_mid["__main__"] = -1 log = "__main__" else: for _, d in userdata.devices.items(): key = str(id(d)) if key in userdata.mqtt_mid and userdata.mqtt_mid[key] == mid: userdata.mqtt_mid[key] = -1 log = d.name d.mqtt_on_subscribe(client, userdata, mid, granted_qos) break _LOGGER.info(f"{log} subscribed: mid={mid} qos={granted_qos}") def mqtt_on_message(client, userdata, msg): topic = msg.topic _LOGGER.info(f"Received {b2s(msg.topic)}, pay {b2s(msg.payload)}") i = topic.rfind("/") if i >= 0 and i < len(topic) - 1: sub = topic[i + 1:] if sub == "devicedl": resp = json.dumps(userdata.devices) client.publish("stat/devicedl", resp) else: for _, d in userdata.devices.items(): d.mqtt_on_message(client, userdata, msg) def mqtt_on_publish(client, userdata, mid): _LOGGER.info("Someone pub mid: " + str(mid)) def mqtt_on_disconnect(client, userdata, rc): _LOGGER.info("disconnect with rc: " + str(rc)) userdata.mqtt_mid = None def mqtt_init(hp, ud): ud.mqtt_mid = None ud.mqtt_subscribe = mqtt_subscribe client = paho.Client(userdata=ud, protocol=paho.MQTTv31) client.on_connect = mqtt_on_connect client.on_message = mqtt_on_message client.on_subscribe = mqtt_on_subscribe client.on_disconnect = mqtt_on_disconnect client.on_publish = mqtt_on_publish _LOGGER.info("mqtt_start (%s:%d)" % hp) client.connect_async(hp[0], port=hp[1]) client.loop_start() return client def mqtt_stop(client): client.on_disconnect = None client.loop_stop() client.disconnect() # Process arguments signal(SIGTERM, sigterm_handler) _LOGGER.info("Parsing args") args = parser.parse_args() mqtt_client = None if len(args.mqtt_host): mqtt_client = mqtt_init((args.mqtt_host, args.mqtt_port), args) _LOGGER.info(str(args)) _LOGGER.info(args.devices) connect_devices(args.devices) actionexec = ActionExecutor() if not args.active_on_finish: EventManager.on('ActionDone', terminate_on_finish, actionexec=actionexec) pars = {'save_filename': args.conf, 'save_devices': args.devices, 'debug': args.debug} EventManager.on('TimerAction', do_timer_action, actionexec=actionexec, **pars) EventManager.on('ActionDiscovery', add_discovered_devices, devices=args.devices, mqtt_client=mqtt_client, mqtt_userdata=args, emit_delay=args.emit_delay) EventManager.on('ExtInsertAction', insert_arrived_action, devices=args.devices, actionexec=actionexec) EventManager.on('ExtChangeState', process_state_change, actionexec=actionexec, devices=args.devices) EventManager.on('ActionDiscovery', save_modified_devices, **pars) EventManager.on('ActionLearnir', save_modified_devices, **pars) EventManager.on('ActionEditraw', save_modified_devices, **pars) EventManager.on('ActionSubscribe', save_modified_devices, **pars) EventManager.on('ActionViewtable1', save_modified_devices, **pars) EventManager.on('ActionInsertKey', save_modified_devices, **pars) EventManager.on('ActionViewtable3', save_modified_devices, **pars) EventManager.on('ActionViewtable4', save_modified_devices, **pars) EventManager.on('ActionStatechange', save_modified_devices, **pars) EventManager.on('ActionStateon', save_modified_devices, **pars) EventManager.on('ActionStateoff', save_modified_devices, **pars) EventManager.on('ActionCreatesh', save_modified_devices, **pars) EventManager.on('ActionDevicedl', handle_device_dl, devices=args.devices, **pars) EventManager.on('ActionExit', terminate_on_finish, actionexec=actionexec, force=True) actionexec.configure(args) if len(args.mqtt_host): actionexec.insert_action(ActionPause("5")) actionexec.insert_action(ActionDiscovery()) actionexec.insert_action(args.actions) stopped = False numv = 2 while threading.active_count() > 1 and numv > 1: try: time.sleep(1) if stopped: thl = threading.enumerate() rv = "" numv = 0 for th in thl: if not th.daemon: numv += 1 rv += th.name + " " _LOGGER.info("TH=%s" % rv) elif term_called: raise KeyboardInterrupt except KeyboardInterrupt: if not stopped: _LOGGER.info("Stopping") stopped = True actionexec.stop() if mqtt_client: mqtt_stop(mqtt_client) for _, k in args.devices.copy().items(): k.on_stop() return 0 except KeyboardInterrupt: # handle keyboard interrupt ### return 0 except Exception as e: if DEBUG or TESTRUN: raise(e) _LOGGER.warning(f"{traceback.format_exc()}") indent = len(program_name) * " " sys.stderr.write(program_name + ": " + repr(e) + "\n") sys.stderr.write(indent + " for help use --help") return 2