def setDim(self, command): DEVICEID = "ebfc16d57ed374932cjqfk" DEVICEIP = "192.168.1.150" DEVICEKEY = "805217605357161b" DEVICEVERS = "us" # Check for environmental variables and always use those if available DDEVICEID = os.getenv("DEVICEID", DEVICEID) DEVICEIP = os.getenv("DEVICEIP", DEVICEIP) DEVICEKEY = os.getenv("DEVICEKEY", DEVICEKEY) DEVICEVERS = os.getenv("DEVICEVERS", DEVICEVERS) LOGGER.info("TreatLife - Smart Switch Test [%s]\n" % tinytuya.__version__) LOGGER.info('TESTING: Device %s at %s with key %s version %s' % (DEVICEID, DEVICEIP, DEVICEKEY, DEVICEVERS)) LOGGER.info('TESTING: Device %s' % (DEVICEIP)) d=tinytuya.BulbDevice(DEVICEID, DEVICEIP, DEVICEKEY) d.set_version(3.3) d.set_socketPersistent(True) ivr_one = 'percent' percent = int(command.get('value')) def set_percent(self, command): percent = int(command.get('value')*10) if percent < 0 or percent > 100: LOGGER.error('Invalid Level {}'.format(percent)) else: d.set_brightness_percentage(percent) #d.set_brightness_percentage(percent) self.setDriver('GV3', percent) LOGGER.info('Dimmer Setpoint = ' + str(percent) +'Level')
def check_params(self): """ This is an example if using custom Params for user and password and an example with a Dictionary """ self.removeNoticesAll() self.addNotice('Hey there, my IP is {}'.format(self.poly.network_interface['addr']),'hello') self.addNotice('Hello Friends! (without key)') default_user = "******" default_password = "******" if 'user' in self.polyConfig['customParams']: self.user = self.polyConfig['customParams']['user'] else: self.user = default_user LOGGER.error('check_params: user not defined in customParams, please add it. Using {}'.format(self.user)) st = False if 'password' in self.polyConfig['customParams']: self.password = self.polyConfig['customParams']['password'] else: self.password = default_password LOGGER.error('check_params: password not defined in customParams, please add it. Using {}'.format(self.password)) st = False # Make sure they are in the params self.addCustomParam({'password': self.password, 'user': self.user, 'some_example': '{ "type": "TheType", "host": "host_or_IP", "port": "port_number" }'}) # Add a notice if they need to change the user/password from the default. if self.user == default_user or self.password == default_password: # This doesn't pass a key to test the old way. self.addNotice('Please set proper user and password in configuration page, and restart this nodeserver') # This one passes a key to test the new way. self.addNotice('This is a test','test')
def start(self): # This grabs the server.json data and checks profile_version is up to date serverdata = self.poly.get_server_data() LOGGER.info('Started Tuya-Switch NodeServer {}'.format(serverdata['version'])) self.check_params() #self.tuyaPlatform(self) #self.uri, 'apiKey', 'apiSecret', 'Controller') #, 'uri', 'apiKey', 'apiSecret' self.poly.add_custom_config_docs("<b>And this is some custom config data</b>")
def tuyaPlatform(self, apiRegion, apiKey, apiSecret, uri, token=None): request = "https://openapi.tuya%s.com/v1.0/%s" % (apiRegion,uri) now = int(time.time()*1000) if(token==None): payload = apiKey + str(now) else: payload = apiKey + token + str(now) # Sign Payload signature = hmac.new( apiSecret.encode('utf-8'), msg=payload.encode('utf-8'), digestmod=hashlib.sha256 ).hexdigest().upper() # Create Header Data headers = {} headers['client_id'] = apiKey headers['sign_method'] = 'HMAC-SHA256' headers['t'] = str(now) headers['sign'] = signature if(token != None): headers['access_token'] = token # Get Token response = requests.get(request, headers=headers) try: response_dict = json.loads(response.content.decode()) except: try: response_dict = json.loads(response.content) except: LOGGER.debug("Failed to get valid JSON response") return(response_dict)
def start(self): """ Optional. Polyglot v2 Interface startup done. Here is where you start your integration. This will run, once the NodeServer connects to Polyglot and gets it's config. In this example I am calling a discovery method. While this is optional, this is where you should start. No need to Super this method, the parent version does nothing. """ # This grabs the server.json data and checks profile_version is up to # date based on the profile_version in server.json as compared to the # last time run which is stored in the DB. When testing just keep # changing the profile_version to some fake string to reload on restart # Only works on local currently.. serverdata = self.poly.get_server_data(check_profile=True) #serverdata['version'] = "testing" LOGGER.info('Started Template NodeServer {}'.format(serverdata['version'])) # Show values on startup if desired. LOGGER.debug('ST=%s',self.getDriver('ST')) self.setDriver('ST', 1) self.heartbeat(0) self.check_params() self.set_debug_level(self.getDriver('GV1')) self.discover() self.poly.add_custom_config_docs("<b>This is some custom config docs data</b>")
def setDim(self, command): DEVICEID = self.DEVICEID DEVICEIP = self.DEVICEIP DEVICEKEY = self.DEVICEKEY DEVICEVERS = self.DEVICEVERS DEVICEID = os.getenv("DEVICEID", DEVICEID) DEVICEIP = os.getenv("DEVICEIP", DEVICEIP) DEVICEKEY = os.getenv("DEVICEKEY", DEVICEKEY) DEVICEVERS = os.getenv("DEVICEVERS", DEVICEVERS) d = tinytuya.BulbDevice(DEVICEID, DEVICEIP, DEVICEKEY) d.set_version(3.3) d.set_socketPersistent(True) ivr_one = 'percent' percent = int(command.get('value')) def set_percent(self, command): percent = int(command.get('value') * 10) if percent < 0 or percent > 100: LOGGER.error('Invalid Level {}'.format(percent)) else: d.set_brightness_percentage( percent) #d.set_brightness_percentage(percent) self.setDriver('GV3', percent) LOGGER.info('Dimmer Setpoint = ' + str(percent) + 'Level')
def shortPoll(self): LOGGER.debug('') self.save_custom_data() self.set_hosts_connected() # Call shortpoll on the camect hosts for id,node in self.nodes_by_id.items(): node.shortPoll()
def set_physical_status(self, val=None, force=False, reportCmd=True): LOGGER.debug(f'{self.lpfx} val={val}') if val is None: val = self.elk.physical_status else: val = int(val) self._set_physical_status(val, force=force, reportCmd=reportCmd)
def set_logical_status(self, val=None, force=False): LOGGER.debug(f'{self.lpfx} val={val}') if val is None: val = self.elk.logical_status else: val = int(val) self._set_logical_status(val, force=force)
def setSwOff(self, command): d = None d._send_receive(payload2) (tinytuya.CONTROL, {'1': True, '2': 50}) self.setDriver('GV2', 0) # Get the status of the device #response = requests.request("GET", url, headers=headers, data=payload) #LOGGER.info('Response. Using {}'str(d._send_receive(payload))) # Command for # Show status of device #self.setDriver('GV2', data, force=True) data = d.status() LOGGER.info('\nCurrent Status of Bulb: %s' % data) #%r #pass #self.addNode(Switch(self, self.address, 'tuyaswitch', 'Switch')) #pass #Poll Switches Here #apiRegion, apiKey, apiSecret, uri, token=None, color=True, # will have to parse out name + 1 to add multiple switches if (data['dps']['20'] == True): state = bold + "On" + dim LOGGER.info(" %s[%s] - %s%s - %s - DPS: %r" % (subbold, name, dim, ip, state, data['dps']))
def execute_command(self, command): LOGGER.debug('executing %s', command) try: self.deviceDriver.executeCommand(command['cmd'], command.get('value')) self.refresh_state() except: LOGGER.exception('Error sending command to ' + self.name)
def setOpenLevel(self, command): LOGGER.info("setOpenLevel: command {}".format(command)) address = command['address'].replace('device', '', 1) if command.get('value'): ol = int(command['value']) else: ol = int(command.get('query', {}).get('OL.uom51')) self.set_value(address, ol)
def _set_triggered(self, val, force=False): if val == 1: self.area.set_last_triggered_zone(self.elk.index) if val == self.triggered and not force: return LOGGER.debug(f'{self.lpfx} val={val} force={force}') self.set_driver('GV1', val) self.triggered = val
def heartbeat(self): LOGGER.debug('heartbeat hb={}'.format(self.hb)) if self.hb == 0: self.reportCmd("DON",2) self.hb = 1 else: self.reportCmd("DOF",2) self.hb = 0
def _shortPoll(self): while (True): self.short_event.wait() LOGGER.debug('start') for an in self._area_nodes: self._area_nodes[an].shortPoll() self.short_event.clear() LOGGER.debug('done')
def stop(self): LOGGER.debug(f"{self.lpfx} NodeServer stopping...") if self.elk is not None: self.elk.disconnect() if self.elk_thread is not None: # Wait for actual termination (if needed) self.elk_thread.join() LOGGER.debug(f"{self.lpfx} NodeServer stopping complete...")
def heartbeat(self): LOGGER.debug(f"{self.lpfx} hb={self.hb}") if self.hb == 0: self.reportCmd("DON", 2) self.hb = 1 else: self.reportCmd("DOF", 2) self.hb = 0
def _longPoll(self): while (True): self.long_event.wait() LOGGER.debug('start') self.heartbeat() self.check_connection() self.long_event.clear() LOGGER.debug('done')
def delete(self): """ Example This is sent by Polyglot upon deletion of the NodeServer. If the process is co-resident and controlled by Polyglot, it will be terminiated within 5 seconds of receiving this message. """ LOGGER.info('Oh God I\'m being deleted. Nooooooooooooooooooooooooooooooooooooooooo.')
def update_status(self,cam): """ Given a cam dict from the Camcect API update all our drivers """ LOGGER.debug(f"{self.lpfx}: disabled={cam['disabled']} is_alert_disabled={cam['is_alert_disabled']} is_streaming={cam['is_streaming']}") self.set_driver('ST',0 if cam['disabled'] else 1) self.set_driver('MODE',0 if cam['is_alert_disabled'] else 1) self.set_driver('GPV', 1 if cam['is_streaming'] else 0)
def discover(self, *args, **kwargs): """ Example Do discovery here. Does not have to be called discovery. Called from example controller start method and from DISCOVER command recieved from ISY as an exmaple. """ if not self.is_connected(): return False # self.addNode(LutronCasetaSmartBridge(self, self.address, 'smartbridgeaddr', 'Caseta Smart Bridge')) devices = self.sb.get_devices() scenes = self.sb.get_scenes() for device_id, device in devices.items(): """ '1': {'device_id': '1', 'name': 'Smart Bridge 2', 'type': 'SmartBridge', 'zone': None, 'current_state': -1}, '3': {'device_id': '3', 'name': 'Living Room_Left Window', 'type': 'SerenaHoneycombShade', 'zone': '2', 'current_state': -1} """ NodeType = None if device.get('type') == "SerenaHoneycombShade": NodeType = SerenaHoneycombShade elif device.get('type') == "QsWirelessShade": NodeType = QsWirelessShade if not NodeType: LOGGER.error("Unsupported Node Type: {}".format(device)) continue address = 'device' + str(device.get('device_id')) LOGGER.info("Adding node: '{}' {}".format(device.get('name'),address)) self.devices[device_id] = self.addNode( NodeType( self, self.address, address, device.get('name'), self.sb, device.get('device_id'), device.get('type'), device.get('zone'), device.get('current_state') ) ) for scene_id, scene in scenes.items(): """ '1': {'scene_id': '1', 'name': 'All Close'}, '2': {'scene_id': '2', 'name': 'All Open'}, '3': {'scene_id': '3', 'name': 'All Halfway'} """ self.addNode( Scene( self, self.address, 'scene' + str(scene.get('scene_id')), scene.get('name'), self.sb ) )
def cmdSetDoWeather(self, cmd): value = int(cmd['value']) if int(self.get_driver(cmd['cmd'])) == value: LOGGER.debug("cmdSetDoWeather: {} already set to {}".format( cmd['cmd'], value)) else: self.set_driver(cmd['cmd'], value) self.do_weather = True if value == 1 else False self.check_weather()
def cmdSetScheduleMode(self, cmd): ''' Set the Schedule Mode, like running, or a hold ''' if int(self.get_driver(cmd['cmd'])) == int(cmd['value']): LOGGER.debug("cmdSetScheduleMode: {}={} already set to {}".format( cmd['cmd'], self.get_driver(cmd['cmd']), cmd['value'])) else: self.pushScheduleMode(cmd['value'])
def check_connection(self): if self.elk is None: st = False elif self.elk.is_connected: st = True else: st = False LOGGER.debug(f"{self.lpfx} st={st} elk_st={self.elk_st}") self.set_st(st)
def turn_off(self, command): # find the right item that matches name for item in data["devices"]: if item["name"] == name: break LOGGER.info("\nTurning Off: %s" % item["name"]) d = tinytuya.OutletDevice(item["id"], item["ip"], item["key"]) d.set_version(float(item["ver"])) d.set_status(False)
def callback(self,event): # {'type': 'alert', 'desc': 'Out Front Door just saw a person.', 'url': 'https://home.camect.com/home/...', # 'cam_id': '96f69defdef1d0b6602a', 'cam_name': 'Out Front Door', 'detected_obj': ['person']} LOGGER.debug(f"{self.lpfx} type={event['type']}") if event['type'] == 'alert': if 'detected_obj' in event: self.detected_obj(event['detected_obj']) else: LOGGER.error(f"Unknown alert, no detected_obj in {event}")
def longPoll(self): """ Optional. This runs every 30 seconds. You would probably update your nodes either here or shortPoll. No need to Super this method the parent version does nothing. The timer can be overriden in the server.json. """ LOGGER.debug('longPoll') self.heartbeat()
def _reAuth(self, reason): # Need to re-auth! LOGGER.error('_reAuth because: {}'.format(reason)) self.addNotice({'reauth': "Must Re-Authorize because {}".format(reason)}) cdata = deepcopy(self.polyConfig['customData']) if not 'tokenData' in cdata: LOGGER.error('No tokenData in customData: {}'.format(cdata)) self.saveCustomDataWait(cdata) self.authorize()
def shortPoll(self): self.set_isy_connected() self.update_config_docs() if self.thread is not None: if not self.thread.is_alive(): self.thread = None LOGGER.error("Thread is dead, restarting.") self.check_params() # Reload in case they changed. self.connect()
def callback(self, obj, changeset): LOGGER.debug(f'{self.lpfx} changeset={changeset}') if 'last_user' in changeset: self.set_user(int(changeset['last_user']) + 1) self.area.set_keypad(self.elk.index + 1) elif 'last_log' in changeset: if 'user_number' in changesset['last_log']: self.set_user(int(changeset['last_log']['user_number']) + 1) self.area.set_keypad(self.elk.index + 1)