def sync(userdata, displayname): """Send a synchronization signal to a device to correct time drift.""" cursor = userdata["cursor"] client = userdata["client"] username = database.getusername(cursor, displayname) if username is None: print("can't find user " + shlex.quote(str(displayname)), file=sys.stderr) return t = int(time.time()) t = t - time.timezone if not time.daylight else t - time.altzone client.publish(username + "/admin", "time " + str(t), qos=1)
def rename(userdata, displayname, newdisplayname): """Change the public display name of a device.""" cursor = userdata["cursor"] configuration = userdata["configuration"] username = database.getusername(cursor, displayname) if username is None: print("can't find user " + shlex.quote(str(displayname)), file=sys.stderr) return if username == configuration["superuser"]: print("can't rename super user", file=sys.stderr) return if not database.rename(cursor, displayname, newdisplayname): print("can't rename the device, the new name may already be in use", file=sys.stderr) return
def schedule(userdata, displayname, event): """Add an operation to be performed represented in an event dictionary to a device's schedule.""" cursor = userdata["cursor"] client = userdata["client"] configuration = userdata["configuration"] username = database.getusername(cursor, displayname) if username is None: print("can't find user " + shlex.quote(str(displayname)), file=sys.stderr) return if username == configuration["superuser"]: print("the schedule is for devices", file=sys.stderr) return cursor.execute("select type, status from profile where username = ?;", (username,)) row = cursor.fetchone() if row is None: print("can't find user " + shlex.quote(str(displayname)), file=sys.stderr) return stype = row[0] status = row[1] if not _validcommand(stype, event.command, status): print("invalid command " + str(event.command) + " for type " + str(stype) + " and status " + str(status), file=sys.stderr) return eventstr = str(event) if event.recurrent: eventstr = eventstr[:10] + "+" + eventstr[10:] else: eventstr = eventstr[:6] + "+" + eventstr[6:] client.publish(username + "/control", eventstr, qos=1) database.addscheduled(cursor, username, event)
def delete(userdata, displayname): """Remove the profile and credentials of a device from the database.""" cursor = userdata["cursor"] db = userdata["database"] configuration = userdata["configuration"] username = database.getusername(cursor, displayname) if username is None: print("can't find user " + shlex.quote(str(displayname)), file=sys.stderr) return if username == configuration["superuser"]: print("can't delete super user", file=sys.stderr) return database.delprofile(cursor, displayname) db.commit() mqtthandlers.kickuser(configuration, username, configuration["devmqttpsk"])
def execute(userdata, displayname, command): """Send a signal to a device to execute a command. The command is first validated to check that the device can act on it, given its type. """ cursor = userdata["cursor"] client = userdata["client"] username = database.getusername(cursor, displayname) if username is None: print("can't find user " + shlex.quote(str(displayname)), file=sys.stderr) return cursor.execute("select type, status from profile where username = ?;", (username,)) row = cursor.fetchone() if row is None: print("can't find user " + shlex.quote(str(displayname)), file=sys.stderr) return stype = row[0] status = row[1] if not _validcommand(stype, command, status): print("invalid command " + str(command) + " for type " + str(stype) + " and status " + str(status), file=sys.stderr) return newstatus = _statustransform(stype, command, status) if newstatus is not None: database.setstatus(cursor, username, newstatus) # the next call should be qos 2 because it is the only operation # that may not be idempotent, but PubSubClient doesn't support it # (and it's too heavyweight anyway) client.publish(username + "/control", command, qos=1)