Re-org and start of API #47

Merged
bmartin5692 merged 10 commits from wip_dev into master 2019-06-21 03:26:06 +02:00
11 changed files with 1064 additions and 981 deletions
Showing only changes of commit 58b3567887 - Show all commits

View file

@ -3,14 +3,12 @@
from bumper.confserver import ConfServer from bumper.confserver import ConfServer
from bumper.mqttserver import MQTTServer, MQTTHelperBot from bumper.mqttserver import MQTTServer, MQTTHelperBot
from bumper.xmppserver import XMPPServer from bumper.xmppserver import XMPPServer
from bumper.models import *
from bumper.db import *
import asyncio import asyncio
import json
from datetime import datetime, timedelta
import os import os
import logging import logging
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
from tinydb import TinyDB, Query
from tinydb.storages import MemoryStorage
import socket import socket
import sys import sys
@ -232,739 +230,6 @@ async def shutdown():
bumperlog.info("Shutdown complete") bumperlog.info("Shutdown complete")
def get_milli_time(timetoconvert):
return int(round(timetoconvert * 1000))
def db_file():
if db:
return db
return os_db_path()
def os_db_path(): # createdir=True):
return os.path.join(data_dir, "bumper.db")
def db_get():
try:
# Will create the database if it doesn't exist
db = TinyDB(db_file())
# Will create the tables if they don't exist
db.table("users", cache_size=0)
db.table("clients", cache_size=0)
db.table("bots", cache_size=0)
db.table("tokens", cache_size=0)
return db
except json.decoder.JSONDecodeError as jerr:
bumperlog.error("JsonErr: {} - Doc: {}".format(jerr.msg, jerr.doc))
except Exception as ex:
bumperlog.error(ex)
class BumperUser(object):
def __init__(self, userid=""):
self.userid = userid
self.devices = []
self.bots = []
def asdict(self):
return {"userid": self.userid, "devices": self.devices, "bots": self.bots}
def user_add(userid):
newuser = BumperUser()
newuser.userid = userid
user = user_get(userid)
if not user:
bumperlog.info("Adding new user with userid: {}".format(newuser.userid))
user_full_upsert(newuser.asdict())
def user_get(userid):
users = db_get().table("users")
User = Query()
return users.get(User.userid == userid)
def user_by_deviceid(deviceid):
users = db_get().table("users")
User = Query()
return users.get(User.devices.any([deviceid]))
def user_full_upsert(user):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
users.upsert(user, User.did == user["userid"])
def user_add_device(userid, devid):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userdevices = list(user["devices"])
if not devid in userdevices:
userdevices.append(devid)
users.upsert({"devices": userdevices}, User.userid == userid)
def user_remove_device(userid, devid):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userdevices = list(user["devices"])
if devid in userdevices:
userdevices.remove(devid)
users.upsert({"devices": userdevices}, User.userid == userid)
def user_add_bot(userid, did):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userbots = list(user["bots"])
if not did in userbots:
userbots.append(did)
users.upsert({"bots": userbots}, User.userid == userid)
def user_remove_bot(userid, did):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userbots = list(user["bots"])
if did in userbots:
userbots.remove(did)
users.upsert({"bots": userbots}, User.userid == userid)
def user_get_tokens(userid):
tokens = db_get().table("tokens")
return tokens.search((Query().userid == userid))
def user_get_token(userid, token):
tokens = db_get().table("tokens")
return tokens.get((Query().userid == userid) & (Query().token == token))
def user_add_token(userid, token):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if not tmptoken:
bumperlog.debug("Adding token {} for userid {}".format(token, userid))
tokens.insert(
{
"userid": userid,
"token": token,
"expiration": "{}".format(
datetime.now() + timedelta(seconds=token_validity_seconds)
),
}
)
def user_revoke_all_tokens(userid):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tsearch = tokens.search(Query().userid == userid)
for i in tsearch:
tokens.remove(doc_ids=[i.doc_id])
def user_revoke_expired_tokens(userid):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tsearch = tokens.search(Query().userid == userid)
for i in tsearch:
if datetime.now() >= datetime.fromisoformat(i["expiration"]):
bumperlog.debug("Removing token {} due to expiration".format(i["token"]))
tokens.remove(doc_ids=[i.doc_id])
def user_revoke_token(userid, token):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if tmptoken:
tokens.remove(doc_ids=[tmptoken.doc_id])
def user_add_authcode(userid, token, authcode):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if tmptoken:
tokens.upsert(
{"authcode": authcode},
((Query().userid == userid) & (Query().token == token)),
)
def user_revoke_authcode(userid, token, authcode):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if tmptoken:
tokens.upsert(
{"authcode": ""}, ((Query().userid == userid) & (Query().token == token))
)
class VacBotDevice(object):
def __init__(
self, did="", vac_bot_device_class="", resource="", name="", nick="", company=""
):
self.vac_bot_device_class = vac_bot_device_class
self.company = company
self.did = did
self.name = name
self.nick = nick
self.resource = resource
self.mqtt_connection = False
self.xmpp_connection = False
def asdict(self):
return {
"class": self.vac_bot_device_class,
"company": self.company,
"did": self.did,
"name": self.name,
"nick": self.nick,
"resource": self.resource,
"mqtt_connection": self.mqtt_connection,
"xmpp_connection": self.xmpp_connection,
}
class GlobalVacBotDevice(VacBotDevice): # EcoVacs Home
UILogicId = ""
ota = True
updateInfo = {"changeLog": "", "needUpdate": False}
icon = ""
deviceName = ""
# EcoVacs Home Product IOT Map - 2019-05-20
# https://portal-ww.ecouser.net/api/pim/product/getProductIotMap
EcoVacsHomeProducts = [
{
"classid": "dl8fht",
"product": {
"UILogicId": "D_600",
"_id": "5acb0fa87c295c0001876ecf",
"icon": "5acc32067c295c0001876eea",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5acc32067c295c0001876eea",
"materialNo": "702-0000-0170",
"name": "DEEBOT 600 Series",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "02uwxm",
"product": {
"UILogicId": "D_OZMO_SLIM10",
"_id": "5ae1481e7ccd1a0001e1f69e",
"icon": "5b1dddc48bc45700014035a1",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b1dddc48bc45700014035a1",
"materialNo": "110-1715-0201",
"name": "DEEBOT OZMO Slim10 Series",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "y79a7u",
"product": {
"UILogicId": "D_OZMO_900",
"_id": "5b04c0227ccd1a0001e1f6a8",
"icon": "5b04c0217ccd1a0001e1f6a7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b04c0217ccd1a0001e1f6a7",
"materialNo": "110-1810-0101",
"name": "DEEBOT OZMO 900 Series",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "jr3pqa",
"product": {
"UILogicId": "D_700",
"_id": "5b43077b8bc457000140363e",
"icon": "5b5ac4cc8d5a56000111e769",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4cc8d5a56000111e769",
"materialNo": "702-0000-0202",
"name": "DEEBOT 711",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "uv242z",
"product": {
"UILogicId": "D_700",
"_id": "5b5149b4ac0b87000148c128",
"icon": "5b5ac4e45f21100001882bb9",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4e45f21100001882bb9",
"materialNo": "702-0000-0205",
"name": "DEEBOT 710",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "ls1ok3",
"product": {
"UILogicId": "D_900",
"_id": "5b6561060506b100015c8868",
"icon": "5ba4a2cb6c2f120001c32839",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5ba4a2cb6c2f120001c32839",
"materialNo": "110-1711-0201",
"name": "DEEBOT 900 Series",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "eyi9jv",
"product": {
"UILogicId": "D_700",
"_id": "5b7b65f364e1680001a08b54",
"icon": "5b7b65f176f7f10001e9a0c2",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b7b65f176f7f10001e9a0c2",
"materialNo": "715",
"name": "DEEBOT 715",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "4zfacv",
"product": {
"UILogicId": "DN_2G",
"_id": "5bf2596f23244a00013f2f13",
"icon": "5c778731280fda0001770ba0",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c778731280fda0001770ba0",
"materialNo": "910",
"name": "DEEBOT 910",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "vi829v",
"product": {
"UILogicId": "DX_5G",
"_id": "5c19a8f3a1e6ee0001782247",
"icon": "5c9c7995e9e9270001354ab4",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c9c7995e9e9270001354ab4",
"materialNo": "920",
"name": "DEEBOT OZMO 920 Series",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "gd4uut",
"product": {
"UILogicId": "DR_935G",
"_id": "5bc8189d68142800016a6937",
"icon": "5c7384767b93c700013f12e7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c7384767b93c700013f12e7",
"materialNo": "960",
"name": "DEEBOT OZMO 960",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": False,
"tmjl": False,
},
},
},
{
"classid": "9akc61",
"product": {
"UILogicId": "D_500",
"_id": "5c763f8263023c0001e7f855",
"icon": "5c932067280fda0001770d7f",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c932067280fda0001770d7f",
"materialNo": "D505",
"name": "DEEBOT 505",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "r8ead0",
"product": {
"UILogicId": "D_500",
"_id": "5c763f63280fda0001770b88",
"icon": "5c93204b63023c0001e7faa7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c93204b63023c0001e7faa7",
"materialNo": "D502",
"name": "DEEBOT 502",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "emzppx",
"product": {
"UILogicId": "D_500",
"_id": "5c763f35280fda0001770b84",
"icon": "5c931fef280fda0001770d7e",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c931fef280fda0001770d7e",
"materialNo": "D501",
"name": "DEEBOT 501",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "vsc5ia",
"product": {
"UILogicId": "D_500",
"_id": "5c763eba280fda0001770b81",
"icon": "5c874326280fda0001770d2a",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c874326280fda0001770d2a",
"materialNo": "D500",
"name": "DEEBOT 500",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "aqdd5p",
"product": {
"UILogicId": "D_900",
"_id": "5cb7cfba179839000114d762",
"icon": "5cb7cfbab72c4d00010e5fc7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5cb7cfbab72c4d00010e5fc7",
"materialNo": "110-1711-0001",
"name": "DEEBOT DE55",
"ota": True,
"supportType": {
"alexa": False,
"assistant": False,
"share": False,
"tmjl": False,
},
},
},
]
class VacBotClient(object):
def __init__(self, userid="", realm="", token=""):
self.userid = userid
self.realm = realm
self.resource = token
self.mqtt_connection = False
self.xmpp_connection = False
def asdict(self):
return {
"userid": self.userid,
"realm": self.realm,
"resource": self.resource,
"mqtt_connection": self.mqtt_connection,
"xmpp_connection": self.xmpp_connection,
}
def get_disconnected_xmpp_clients():
clients = db_get().table("clients")
Client = Query()
return clients.search(Client.xmpp_connection == False)
def check_authcode(uid, authcode):
bumperlog.debug("Checking for authcode: {}".format(authcode))
tokens = db_get().table("tokens")
tmpauth = tokens.get(
(Query().authcode == authcode)
& ( # Match authcode
(Query().userid == uid.replace("fuid_", ""))
| (Query().userid == "fuid_{}".format(uid))
) # Userid with or without fuid_
)
if tmpauth:
return True
return False
def loginByItToken(authcode):
bumperlog.debug("Checking for authcode: {}".format(authcode))
tokens = db_get().table("tokens")
tmpauth = tokens.get(
(Query().authcode == authcode)
# & ( # Match authcode
# (Query().userid == uid.replace("fuid_", ""))
# | (Query().userid == "fuid_{}".format(uid))
# ) # Userid with or without fuid_
)
if tmpauth:
return {"token": tmpauth["token"], "userid": tmpauth["userid"]}
return {}
def check_token(uid, token):
bumperlog.debug("Checking for token: {}".format(token))
tokens = db_get().table("tokens")
tmpauth = tokens.get(
(Query().token == token)
& ( # Match token
(Query().userid == uid.replace("fuid_", ""))
| (Query().userid == "fuid_{}".format(uid))
) # Userid with or without fuid_
)
if tmpauth:
return True
return False
def revoke_expired_tokens():
tokens = db_get().table("tokens").all()
for i in tokens:
if datetime.now() >= datetime.fromisoformat(i["expiration"]):
bumperlog.debug("Removing token {} due to expiration".format(i["token"]))
db_get().table("tokens").remove(doc_ids=[i.doc_id])
def bot_add(sn, did, devclass, resource, company):
newbot = VacBotDevice()
newbot.did = did
newbot.name = sn
newbot.vac_bot_device_class = devclass
newbot.resource = resource
newbot.company = company
bot = bot_get(did)
if not bot: # Not existing bot in database
if (
not devclass == "" or "@" not in sn or "tmp" not in sn
): # try to prevent bad additions to the bot list
bumperlog.info(
"Adding new bot with SN: {} DID: {}".format(newbot.name, newbot.did)
)
bot_full_upsert(newbot.asdict())
def bot_remove(did):
bots = db_get().table("bots")
bot = bot_get(did)
bots.remove(doc_ids=[bot.doc_id])
def bot_get(did):
bots = db_get().table("bots")
Bot = Query()
return bots.get(Bot.did == did)
def bot_toEcoVacsHome_JSON(bot): # EcoVacs Home
for botprod in EcoVacsHomeProducts:
if botprod["classid"] == bot["class"]:
bot["UILogicId"] = botprod["product"]["UILogicId"]
bot["ota"] = botprod["product"]["ota"]
bot["icon"] = botprod["product"]["iconUrl"]
return json.dumps(
bot, default=lambda o: o.__dict__, sort_keys=False
) # , indent=4)
def bot_full_upsert(vacbot):
bots = db_get().table("bots")
Bot = Query()
bots.upsert(vacbot, Bot.did == vacbot["did"])
def bot_set_nick(did, nick):
bots = db_get().table("bots")
Bot = Query()
bots.upsert({"nick": nick}, Bot.did == did)
def bot_set_mqtt(did, mqtt):
bots = db_get().table("bots")
Bot = Query()
bots.upsert({"mqtt_connection": mqtt}, Bot.did == did)
def bot_set_xmpp(did, xmpp):
bots = db_get().table("bots")
Bot = Query()
bots.upsert({"xmpp_connection": xmpp}, Bot.did == did)
def client_add(userid, realm, resource):
newclient = VacBotClient()
newclient.userid = userid
newclient.realm = realm
newclient.resource = resource
client = client_get(resource)
if not client:
bumperlog.info("Adding new client with resource {}".format(newclient.resource))
client_full_upsert(newclient.asdict())
def client_get(resource):
clients = db_get().table("clients")
Client = Query()
return clients.get(Client.resource == resource)
def client_full_upsert(client):
clients = db_get().table("clients")
Client = Query()
clients.upsert(client, Client.resource == client["resource"])
def client_set_mqtt(resource, mqtt):
clients = db_get().table("clients")
Client = Query()
clients.upsert({"mqtt_connection": mqtt}, Client.resource == resource)
def client_set_xmpp(resource, xmpp):
clients = db_get().table("clients")
Client = Query()
clients.upsert({"xmpp_connection": xmpp}, Client.resource == resource)
RETURN_API_SUCCESS = "0000"
ERR_ACTIVATE_TOKEN_TIMEOUT = "1006"
ERR_COMMON = "0001"
ERR_DEFAULT = "9000"
ERR_EMAIL_NON_EXIST = "1002"
ERR_EMAIL_SEND_TIME_LIMIT = "1011"
ERR_EMAIL_USED = "1001"
ERR_INTERFACE_AUTH = "0002"
ERR_PARAM_INVALID = "0003"
ERR_PWD_WRONG = "1005"
ERR_RESET_PWD_TOKEN_TIMEOUT = "1007"
ERR_TIMESTAMP_INVALID = "0005"
ERR_TOKEN_INVALID = "0004"
ERR_USER_DISABLE = "1004"
ERR_USER_NOT_ACTIVATED = "1003"
ERR_WRONG_COMFIRM_PWD = "10010"
ERR_WRONG_EMAIL_ADDRESS = "1008"
ERR_WRONG_PWD_FROMATE = "1009"
API_ERRORS = {
RETURN_API_SUCCESS: "0000",
ERR_ACTIVATE_TOKEN_TIMEOUT: "1006",
ERR_COMMON: "0001",
ERR_DEFAULT: "9000",
ERR_EMAIL_NON_EXIST: "1002",
ERR_EMAIL_SEND_TIME_LIMIT: "1011",
ERR_EMAIL_USED: "1001",
ERR_INTERFACE_AUTH: "0002",
ERR_PARAM_INVALID: "0003",
ERR_PWD_WRONG: "1005",
ERR_RESET_PWD_TOKEN_TIMEOUT: "1007",
ERR_TIMESTAMP_INVALID: "0005",
ERR_TOKEN_INVALID: "0004",
ERR_USER_DISABLE: "1004",
ERR_USER_NOT_ACTIVATED: "1003",
ERR_WRONG_COMFIRM_PWD: "10010",
ERR_WRONG_EMAIL_ADDRESS: "1008",
ERR_WRONG_PWD_FROMATE: "1009",
}
def create_certs(): def create_certs():
import platform import platform
import os import os
@ -1015,6 +280,7 @@ def create_certs():
def first_run(): def first_run():
create_certs() create_certs()
def main(argv=None): def main(argv=None):
import argparse import argparse

View file

@ -6,6 +6,7 @@ import ssl
import string import string
import random import random
import bumper import bumper
from bumper.models import *
from datetime import datetime, timedelta from datetime import datetime, timedelta
import asyncio import asyncio
from aiohttp import web from aiohttp import web
@ -36,25 +37,6 @@ logging.getLogger("aiohttp.access").addFilter(
) # Add logging filter above to aiohttp.access ) # Add logging filter above to aiohttp.access
class EcoVacs_Login:
accessToken = ""
country = ""
email = ""
uid = ""
username = ""
def toJSON(self):
return json.dumps(
self, default=lambda o: o.__dict__, sort_keys=False
) # , indent=4)
class EcoVacsHome_Login(EcoVacs_Login):
loginName = ""
mobile = ""
ucUid = ""
class ConfServer: class ConfServer:
def __init__(self, address, usessl=False, helperbot=None): def __init__(self, address, usessl=False, helperbot=None):
self.helperbot = helperbot self.helperbot = helperbot
@ -66,6 +48,9 @@ class ConfServer:
self.site = None self.site = None
self.runner = None self.runner = None
def get_milli_time(self, timetoconvert):
return int(round(timetoconvert * 1000))
def confserver_app(self): def confserver_app(self):
self.app = web.Application(loop=asyncio.get_event_loop()) self.app = web.Application(loop=asyncio.get_event_loop())
@ -214,8 +199,11 @@ class ConfServer:
bots = bumper.db_get().table("bots").all() bots = bumper.db_get().table("bots").all()
clients = bumper.db_get().table("clients").all() clients = bumper.db_get().table("clients").all()
helperbot = self.helperbot.Client.session.transitions.state helperbot = self.helperbot.Client.session.transitions.state
all = {'bots':bots, 'clients':clients, 'helperbot': [{'state': helperbot}]} all = {
"bots": bots,
"clients": clients,
"helperbot": [{"state": helperbot}],
}
return web.json_response(all) return web.json_response(all)
@ -261,7 +249,7 @@ class ConfServer:
login_details.email = "null@null.com" login_details.email = "null@null.com"
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": API_ERRORS[RETURN_API_SUCCESS],
"data": json.loads(login_details.toJSON()), "data": json.loads(login_details.toJSON()),
# { # {
# "accessToken": self.generate_token(tmpuser), # Generate a token # "accessToken": self.generate_token(tmpuser), # Generate a token
@ -271,7 +259,7 @@ class ConfServer:
# "username": "fusername_{}".format(tmpuser["userid"]), # "username": "fusername_{}".format(tmpuser["userid"]),
# }, # },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time( "time": self.self.get_milli_time(
datetime.utcnow().timestamp() datetime.utcnow().timestamp()
), ),
} }
@ -282,7 +270,7 @@ class ConfServer:
"code": bumper.ERR_USER_NOT_ACTIVATED, "code": bumper.ERR_USER_NOT_ACTIVATED,
"data": None, "data": None,
"msg": "当前密码错误", "msg": "当前密码错误",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -328,7 +316,7 @@ class ConfServer:
"loginName": login_details.loginName, "loginName": login_details.loginName,
}, },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -364,7 +352,7 @@ class ConfServer:
# "username": "fusername_{}".format(tmpuser["userid"]), # "username": "fusername_{}".format(tmpuser["userid"]),
# }, # },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -373,7 +361,7 @@ class ConfServer:
"code": bumper.ERR_TOKEN_INVALID, "code": bumper.ERR_TOKEN_INVALID,
"data": None, "data": None,
"msg": "当前密码错误", "msg": "当前密码错误",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -464,7 +452,7 @@ class ConfServer:
# "username": "fusername_{}".format(tmpuser["userid"]), # "username": "fusername_{}".format(tmpuser["userid"]),
# }, # },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return body return body
@ -488,7 +476,7 @@ class ConfServer:
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
"data": None, "data": None,
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -530,7 +518,7 @@ class ConfServer:
}, },
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time( "time": self.get_milli_time(
datetime.utcnow().timestamp() datetime.utcnow().timestamp()
), ),
} }
@ -542,7 +530,7 @@ class ConfServer:
"ecovacsUid": request.query["uid"], "ecovacsUid": request.query["uid"],
}, },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time( "time": self.get_milli_time(
datetime.utcnow().timestamp() datetime.utcnow().timestamp()
), ),
} }
@ -552,7 +540,7 @@ class ConfServer:
"code": bumper.ERR_TOKEN_INVALID, "code": bumper.ERR_TOKEN_INVALID,
"data": None, "data": None,
"msg": "当前密码错误", "msg": "当前密码错误",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -574,7 +562,7 @@ class ConfServer:
"v": None, "v": None,
}, },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -599,7 +587,7 @@ class ConfServer:
}, },
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -614,7 +602,7 @@ class ConfServer:
"data": None, "data": None,
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -629,7 +617,7 @@ class ConfServer:
"data": None, "data": None,
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -644,7 +632,7 @@ class ConfServer:
"data": None, "data": None,
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -659,7 +647,7 @@ class ConfServer:
"data": "N", "data": "N",
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -683,7 +671,7 @@ class ConfServer:
"data": {"hasNextPage": 0, "items": []}, "data": {"hasNextPage": 0, "items": []},
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -703,7 +691,7 @@ class ConfServer:
}, },
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -725,7 +713,7 @@ class ConfServer:
}, },
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -757,14 +745,14 @@ class ConfServer:
], ],
"msg": "操作成功", "msg": "操作成功",
"success": True, "success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
else: else:
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
"data": [], "data": [],
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
@ -774,7 +762,7 @@ class ConfServer:
async def handle_homePageAlert(self, request): async def handle_homePageAlert(self, request):
try: try:
nextAlert = bumper.get_milli_time( nextAlert = self.get_milli_time(
(datetime.now() + timedelta(hours=12)).timestamp() (datetime.now() + timedelta(hours=12)).timestamp()
) )
@ -786,10 +774,10 @@ class ConfServer:
"hasCampaign": "N", "hasCampaign": "N",
"imageUrl": None, "imageUrl": None,
"nextAlertTime": nextAlert, "nextAlertTime": nextAlert,
"serverTime": bumper.get_milli_time(datetime.utcnow().timestamp()), "serverTime": self.get_milli_time(datetime.utcnow().timestamp()),
}, },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": self.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)

373
bumper/db.py Normal file
View file

@ -0,0 +1,373 @@
#!/usr/bin/env python3
import bumper
from bumper.models import VacBotClient, VacBotDevice, BumperUser, EcoVacsHomeProducts
from tinydb import TinyDB, Query
from tinydb.storages import MemoryStorage
from datetime import datetime, timedelta
import os
import json
import logging
bumperlog = logging.getLogger("bumper")
def db_file():
if bumper.db:
return bumper.db
return os_db_path()
def os_db_path(): # createdir=True):
return os.path.join(bumper.data_dir, "bumper.db")
def db_get():
try:
# Will create the database if it doesn't exist
db = TinyDB(db_file())
# Will create the tables if they don't exist
db.table("users", cache_size=0)
db.table("clients", cache_size=0)
db.table("bots", cache_size=0)
db.table("tokens", cache_size=0)
return db
except json.decoder.JSONDecodeError as jerr:
bumperlog.error("JsonErr: {} - Doc: {}".format(jerr.msg, jerr.doc))
except Exception as ex:
bumperlog.error(ex)
def user_add(userid):
newuser = BumperUser()
newuser.userid = userid
user = user_get(userid)
if not user:
bumperlog.info("Adding new user with userid: {}".format(newuser.userid))
user_full_upsert(newuser.asdict())
def user_get(userid):
users = db_get().table("users")
User = Query()
return users.get(User.userid == userid)
def user_by_deviceid(deviceid):
users = db_get().table("users")
User = Query()
return users.get(User.devices.any([deviceid]))
def user_full_upsert(user):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
users.upsert(user, User.did == user["userid"])
def user_add_device(userid, devid):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userdevices = list(user["devices"])
if not devid in userdevices:
userdevices.append(devid)
users.upsert({"devices": userdevices}, User.userid == userid)
def user_remove_device(userid, devid):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userdevices = list(user["devices"])
if devid in userdevices:
userdevices.remove(devid)
users.upsert({"devices": userdevices}, User.userid == userid)
def user_add_bot(userid, did):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userbots = list(user["bots"])
if not did in userbots:
userbots.append(did)
users.upsert({"bots": userbots}, User.userid == userid)
def user_remove_bot(userid, did):
opendb = db_get()
with opendb:
users = opendb.table("users")
User = Query()
user = users.get(User.userid == userid)
userbots = list(user["bots"])
if did in userbots:
userbots.remove(did)
users.upsert({"bots": userbots}, User.userid == userid)
def user_get_tokens(userid):
tokens = db_get().table("tokens")
return tokens.search((Query().userid == userid))
def user_get_token(userid, token):
tokens = db_get().table("tokens")
return tokens.get((Query().userid == userid) & (Query().token == token))
def user_add_token(userid, token):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if not tmptoken:
bumperlog.debug("Adding token {} for userid {}".format(token, userid))
tokens.insert(
{
"userid": userid,
"token": token,
"expiration": "{}".format(
datetime.now()
+ timedelta(seconds=bumper.token_validity_seconds)
),
}
)
def user_revoke_all_tokens(userid):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tsearch = tokens.search(Query().userid == userid)
for i in tsearch:
tokens.remove(doc_ids=[i.doc_id])
def user_revoke_expired_tokens(userid):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tsearch = tokens.search(Query().userid == userid)
for i in tsearch:
if datetime.now() >= datetime.fromisoformat(i["expiration"]):
bumperlog.debug(
"Removing token {} due to expiration".format(i["token"])
)
tokens.remove(doc_ids=[i.doc_id])
def user_revoke_token(userid, token):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if tmptoken:
tokens.remove(doc_ids=[tmptoken.doc_id])
def user_add_authcode(userid, token, authcode):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if tmptoken:
tokens.upsert(
{"authcode": authcode},
((Query().userid == userid) & (Query().token == token)),
)
def user_revoke_authcode(userid, token, authcode):
opendb = db_get()
with opendb:
tokens = opendb.table("tokens")
tmptoken = tokens.get((Query().userid == userid) & (Query().token == token))
if tmptoken:
tokens.upsert(
{"authcode": ""},
((Query().userid == userid) & (Query().token == token)),
)
def get_disconnected_xmpp_clients():
clients = db_get().table("clients")
Client = Query()
return clients.search(Client.xmpp_connection == False)
def check_authcode(uid, authcode):
bumperlog.debug("Checking for authcode: {}".format(authcode))
tokens = db_get().table("tokens")
tmpauth = tokens.get(
(Query().authcode == authcode)
& ( # Match authcode
(Query().userid == uid.replace("fuid_", ""))
| (Query().userid == "fuid_{}".format(uid))
) # Userid with or without fuid_
)
if tmpauth:
return True
return False
def loginByItToken(authcode):
bumperlog.debug("Checking for authcode: {}".format(authcode))
tokens = db_get().table("tokens")
tmpauth = tokens.get(
(Query().authcode == authcode)
# & ( # Match authcode
# (Query().userid == uid.replace("fuid_", ""))
# | (Query().userid == "fuid_{}".format(uid))
# ) # Userid with or without fuid_
)
if tmpauth:
return {"token": tmpauth["token"], "userid": tmpauth["userid"]}
return {}
def check_token(uid, token):
bumperlog.debug("Checking for token: {}".format(token))
tokens = db_get().table("tokens")
tmpauth = tokens.get(
(Query().token == token)
& ( # Match token
(Query().userid == uid.replace("fuid_", ""))
| (Query().userid == "fuid_{}".format(uid))
) # Userid with or without fuid_
)
if tmpauth:
return True
return False
def revoke_expired_tokens():
tokens = db_get().table("tokens").all()
for i in tokens:
if datetime.now() >= datetime.fromisoformat(i["expiration"]):
bumperlog.debug("Removing token {} due to expiration".format(i["token"]))
db_get().table("tokens").remove(doc_ids=[i.doc_id])
def bot_add(sn, did, devclass, resource, company):
newbot = VacBotDevice()
newbot.did = did
newbot.name = sn
newbot.vac_bot_device_class = devclass
newbot.resource = resource
newbot.company = company
bot = bot_get(did)
if not bot: # Not existing bot in database
if (
not devclass == "" or "@" not in sn or "tmp" not in sn
): # try to prevent bad additions to the bot list
bumperlog.info(
"Adding new bot with SN: {} DID: {}".format(newbot.name, newbot.did)
)
bot_full_upsert(newbot.asdict())
def bot_remove(did):
bots = db_get().table("bots")
bot = bot_get(did)
bots.remove(doc_ids=[bot.doc_id])
def bot_get(did):
bots = db_get().table("bots")
Bot = Query()
return bots.get(Bot.did == did)
def bot_toEcoVacsHome_JSON(bot): # EcoVacs Home
for botprod in EcoVacsHomeProducts:
if botprod["classid"] == bot["class"]:
bot["UILogicId"] = botprod["product"]["UILogicId"]
bot["ota"] = botprod["product"]["ota"]
bot["icon"] = botprod["product"]["iconUrl"]
return json.dumps(
bot, default=lambda o: o.__dict__, sort_keys=False
) # , indent=4)
def bot_full_upsert(vacbot):
bots = db_get().table("bots")
Bot = Query()
bots.upsert(vacbot, Bot.did == vacbot["did"])
def bot_set_nick(did, nick):
bots = db_get().table("bots")
Bot = Query()
bots.upsert({"nick": nick}, Bot.did == did)
def bot_set_mqtt(did, mqtt):
bots = db_get().table("bots")
Bot = Query()
bots.upsert({"mqtt_connection": mqtt}, Bot.did == did)
def bot_set_xmpp(did, xmpp):
bots = db_get().table("bots")
Bot = Query()
bots.upsert({"xmpp_connection": xmpp}, Bot.did == did)
def client_add(userid, realm, resource):
newclient = VacBotClient()
newclient.userid = userid
newclient.realm = realm
newclient.resource = resource
client = client_get(resource)
if not client:
bumperlog.info("Adding new client with resource {}".format(newclient.resource))
client_full_upsert(newclient.asdict())
def client_get(resource):
clients = db_get().table("clients")
Client = Query()
return clients.get(Client.resource == resource)
def client_full_upsert(client):
clients = db_get().table("clients")
Client = Query()
clients.upsert(client, Client.resource == client["resource"])
def client_set_mqtt(resource, mqtt):
clients = db_get().table("clients")
Client = Query()
clients.upsert({"mqtt_connection": mqtt}, Client.resource == resource)
def client_set_xmpp(resource, xmpp):
clients = db_get().table("clients")
Client = Query()
clients.upsert({"xmpp_connection": xmpp}, Client.resource == resource)

401
bumper/models.py Normal file
View file

@ -0,0 +1,401 @@
#!/usr/bin/env python3
import json
class VacBotDevice(object):
def __init__(
self, did="", vac_bot_device_class="", resource="", name="", nick="", company=""
):
self.vac_bot_device_class = vac_bot_device_class
self.company = company
self.did = did
self.name = name
self.nick = nick
self.resource = resource
self.mqtt_connection = False
self.xmpp_connection = False
def asdict(self):
return {
"class": self.vac_bot_device_class,
"company": self.company,
"did": self.did,
"name": self.name,
"nick": self.nick,
"resource": self.resource,
"mqtt_connection": self.mqtt_connection,
"xmpp_connection": self.xmpp_connection,
}
class BumperUser(object):
def __init__(self, userid=""):
self.userid = userid
self.devices = []
self.bots = []
def asdict(self):
return {"userid": self.userid, "devices": self.devices, "bots": self.bots}
class GlobalVacBotDevice(VacBotDevice): # EcoVacs Home
UILogicId = ""
ota = True
updateInfo = {"changeLog": "", "needUpdate": False}
icon = ""
deviceName = ""
class VacBotClient(object):
def __init__(self, userid="", realm="", token=""):
self.userid = userid
self.realm = realm
self.resource = token
self.mqtt_connection = False
self.xmpp_connection = False
def asdict(self):
return {
"userid": self.userid,
"realm": self.realm,
"resource": self.resource,
"mqtt_connection": self.mqtt_connection,
"xmpp_connection": self.xmpp_connection,
}
class EcoVacs_Login:
accessToken = ""
country = ""
email = ""
uid = ""
username = ""
def toJSON(self):
return json.dumps(
self, default=lambda o: o.__dict__, sort_keys=False
) # , indent=4)
class EcoVacsHome_Login(EcoVacs_Login):
loginName = ""
mobile = ""
ucUid = ""
# EcoVacs Home Product IOT Map - 2019-05-20
# https://portal-ww.ecouser.net/api/pim/product/getProductIotMap
EcoVacsHomeProducts = [
{
"classid": "dl8fht",
"product": {
"UILogicId": "D_600",
"_id": "5acb0fa87c295c0001876ecf",
"icon": "5acc32067c295c0001876eea",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5acc32067c295c0001876eea",
"materialNo": "702-0000-0170",
"name": "DEEBOT 600 Series",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "02uwxm",
"product": {
"UILogicId": "D_OZMO_SLIM10",
"_id": "5ae1481e7ccd1a0001e1f69e",
"icon": "5b1dddc48bc45700014035a1",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b1dddc48bc45700014035a1",
"materialNo": "110-1715-0201",
"name": "DEEBOT OZMO Slim10 Series",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "y79a7u",
"product": {
"UILogicId": "D_OZMO_900",
"_id": "5b04c0227ccd1a0001e1f6a8",
"icon": "5b04c0217ccd1a0001e1f6a7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b04c0217ccd1a0001e1f6a7",
"materialNo": "110-1810-0101",
"name": "DEEBOT OZMO 900 Series",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "jr3pqa",
"product": {
"UILogicId": "D_700",
"_id": "5b43077b8bc457000140363e",
"icon": "5b5ac4cc8d5a56000111e769",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4cc8d5a56000111e769",
"materialNo": "702-0000-0202",
"name": "DEEBOT 711",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "uv242z",
"product": {
"UILogicId": "D_700",
"_id": "5b5149b4ac0b87000148c128",
"icon": "5b5ac4e45f21100001882bb9",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4e45f21100001882bb9",
"materialNo": "702-0000-0205",
"name": "DEEBOT 710",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "ls1ok3",
"product": {
"UILogicId": "D_900",
"_id": "5b6561060506b100015c8868",
"icon": "5ba4a2cb6c2f120001c32839",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5ba4a2cb6c2f120001c32839",
"materialNo": "110-1711-0201",
"name": "DEEBOT 900 Series",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "eyi9jv",
"product": {
"UILogicId": "D_700",
"_id": "5b7b65f364e1680001a08b54",
"icon": "5b7b65f176f7f10001e9a0c2",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b7b65f176f7f10001e9a0c2",
"materialNo": "715",
"name": "DEEBOT 715",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "4zfacv",
"product": {
"UILogicId": "DN_2G",
"_id": "5bf2596f23244a00013f2f13",
"icon": "5c778731280fda0001770ba0",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c778731280fda0001770ba0",
"materialNo": "910",
"name": "DEEBOT 910",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "vi829v",
"product": {
"UILogicId": "DX_5G",
"_id": "5c19a8f3a1e6ee0001782247",
"icon": "5c9c7995e9e9270001354ab4",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c9c7995e9e9270001354ab4",
"materialNo": "920",
"name": "DEEBOT OZMO 920 Series",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "gd4uut",
"product": {
"UILogicId": "DR_935G",
"_id": "5bc8189d68142800016a6937",
"icon": "5c7384767b93c700013f12e7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c7384767b93c700013f12e7",
"materialNo": "960",
"name": "DEEBOT OZMO 960",
"ota": True,
"supportType": {
"alexa": True,
"assistant": True,
"share": False,
"tmjl": False,
},
},
},
{
"classid": "9akc61",
"product": {
"UILogicId": "D_500",
"_id": "5c763f8263023c0001e7f855",
"icon": "5c932067280fda0001770d7f",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c932067280fda0001770d7f",
"materialNo": "D505",
"name": "DEEBOT 505",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "r8ead0",
"product": {
"UILogicId": "D_500",
"_id": "5c763f63280fda0001770b88",
"icon": "5c93204b63023c0001e7faa7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c93204b63023c0001e7faa7",
"materialNo": "D502",
"name": "DEEBOT 502",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "emzppx",
"product": {
"UILogicId": "D_500",
"_id": "5c763f35280fda0001770b84",
"icon": "5c931fef280fda0001770d7e",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c931fef280fda0001770d7e",
"materialNo": "D501",
"name": "DEEBOT 501",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "vsc5ia",
"product": {
"UILogicId": "D_500",
"_id": "5c763eba280fda0001770b81",
"icon": "5c874326280fda0001770d2a",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c874326280fda0001770d2a",
"materialNo": "D500",
"name": "DEEBOT 500",
"ota": False,
"supportType": {
"alexa": True,
"assistant": True,
"share": True,
"tmjl": False,
},
},
},
{
"classid": "aqdd5p",
"product": {
"UILogicId": "D_900",
"_id": "5cb7cfba179839000114d762",
"icon": "5cb7cfbab72c4d00010e5fc7",
"iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5cb7cfbab72c4d00010e5fc7",
"materialNo": "110-1711-0001",
"name": "DEEBOT DE55",
"ota": True,
"supportType": {
"alexa": False,
"assistant": False,
"share": False,
"tmjl": False,
},
},
},
]
RETURN_API_SUCCESS = "0000"
ERR_ACTIVATE_TOKEN_TIMEOUT = "1006"
ERR_COMMON = "0001"
ERR_DEFAULT = "9000"
ERR_EMAIL_NON_EXIST = "1002"
ERR_EMAIL_SEND_TIME_LIMIT = "1011"
ERR_EMAIL_USED = "1001"
ERR_INTERFACE_AUTH = "0002"
ERR_PARAM_INVALID = "0003"
ERR_PWD_WRONG = "1005"
ERR_RESET_PWD_TOKEN_TIMEOUT = "1007"
ERR_TIMESTAMP_INVALID = "0005"
ERR_TOKEN_INVALID = "0004"
ERR_USER_DISABLE = "1004"
ERR_USER_NOT_ACTIVATED = "1003"
ERR_WRONG_COMFIRM_PWD = "10010"
ERR_WRONG_EMAIL_ADDRESS = "1008"
ERR_WRONG_PWD_FROMATE = "1009"
API_ERRORS = {
RETURN_API_SUCCESS: "0000",
ERR_ACTIVATE_TOKEN_TIMEOUT: "1006",
ERR_COMMON: "0001",
ERR_DEFAULT: "9000",
ERR_EMAIL_NON_EXIST: "1002",
ERR_EMAIL_SEND_TIME_LIMIT: "1011",
ERR_EMAIL_USED: "1001",
ERR_INTERFACE_AUTH: "0002",
ERR_PARAM_INVALID: "0003",
ERR_PWD_WRONG: "1005",
ERR_RESET_PWD_TOKEN_TIMEOUT: "1007",
ERR_TIMESTAMP_INVALID: "0005",
ERR_TOKEN_INVALID: "0004",
ERR_USER_DISABLE: "1004",
ERR_USER_NOT_ACTIVATED: "1003",
ERR_WRONG_COMFIRM_PWD: "10010",
ERR_WRONG_EMAIL_ADDRESS: "1008",
ERR_WRONG_PWD_FROMATE: "1009",
}

View file

@ -103,17 +103,19 @@ class MQTTHelperBot:
) )
elif str(message.topic).split("/")[1] == "atr": elif str(message.topic).split("/")[1] == "atr":
# Broadcast message received on atr # Broadcast message received on atr
helperbotlog.debug(
"Received Broadcast - Topic: {} - Message: {}".format(
message.topic, str(message.data.decode("utf-8"))
)
)
if str(message.topic).split("/")[2] == "errors": if str(message.topic).split("/")[2] == "errors":
boterrorlog.error( boterrorlog.error(
"Received Error - Topic: {} - Message: {}".format( "Received Error - Topic: {} - Message: {}".format(
message.topic, str(message.data.decode("utf-8")) message.topic, str(message.data.decode("utf-8"))
) )
) )
else:
helperbotlog.debug(
"Received Broadcast - Topic: {} - Message: {}".format(
message.topic, str(message.data.decode("utf-8"))
)
)
else: else:
helperbotlog.debug( helperbotlog.debug(
"Received Message - Topic: {} - Message: {}".format( "Received Message - Topic: {} - Message: {}".format(

View file

@ -7,6 +7,7 @@ import json
import tinydb import tinydb
import pytest_aiohttp import pytest_aiohttp
import pytest_asyncio import pytest_asyncio
import datetime, time
from aiohttp import web from aiohttp import web
@ -42,6 +43,19 @@ async def test_confserver_no_ssl():
conf_server.confserver_app() conf_server.confserver_app()
asyncio.create_task(conf_server.start_server()) asyncio.create_task(conf_server.start_server())
def test_get_milli_time():
cserv = create_confserver()
assert (
cserv.get_milli_time(
datetime.datetime(
2018, 1, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc
).timestamp()
)
== 1514768400000
)
# Comment out test_base until api changes are complete # Comment out test_base until api changes are complete
""" async def test_base(aiohttp_client): """ async def test_base(aiohttp_client):
remove_existing_db() remove_existing_db()

145
tests/test_db.py Normal file
View file

@ -0,0 +1,145 @@
#!/usr/bin/env python3
import bumper
from bumper.models import VacBotClient, VacBotDevice, BumperUser, EcoVacsHomeProducts
from tinydb import TinyDB, Query
from tinydb.storages import MemoryStorage
from datetime import datetime, timedelta
import os
import json
import logging
def test_db_path():
bumper.db = None
assert bumper.db_file() == os.path.join(bumper.data_dir, "bumper.db")
def test_user_db():
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.user_add("testuser") # Add testuser
assert (
bumper.user_get("testuser")["userid"] == "testuser"
) # Test that testuser was created and returned
bumper.user_add_device("testuser", "dev_1234") # Add device to testuser
assert (
bumper.user_by_deviceid("dev_1234")["userid"] == "testuser"
) # Test that testuser was found by deviceid
bumper.user_remove_device("testuser", "dev_1234") # Remove device from testuser
assert "dev_1234" not in bumper.user_get("testuser")["devices"]
# Test that dev_1234 was not found in testuser devices
bumper.user_add_bot("testuser", "bot_1234") # Add bot did to testuser
assert "bot_1234" in bumper.user_get("testuser")["bots"]
# Test that bot was found in testuser's bot list
bumper.user_remove_bot("testuser", "bot_1234") # Remove bot did from testuser
assert "bot_1234" not in bumper.user_get("testuser")["bots"]
# Test that bot was not found in testuser's bot list
bumper.user_add_token("testuser", "token_1234") # Add token to testuser
assert bumper.check_token("testuser", "token_1234")
# Test that token was found for testuser
assert bumper.user_get_token("testuser", "token_1234")
# Test that token was returned for testuser
bumper.user_add_authcode(
"testuser", "token_1234", "auth_1234"
) # Add authcode to token_1234 for testuser
assert bumper.check_authcode("testuser", "auth_1234")
# Test that authcode was found for testuser
bumper.user_revoke_authcode(
"testuser", "token_1234", "auth_1234"
) # Remove authcode from testuser
assert bumper.check_authcode("testuser", "auth_1234") == False
# Test that authcode was not found for testuser
bumper.user_revoke_token("testuser", "token_1234") # Remove token from testuser
assert (
bumper.check_token("testuser", "token_1234") == False
) # Test that token was not found for testuser
bumper.user_add_token("testuser", "token_1234") # Add token_1234
bumper.user_add_token("testuser", "token_4321") # Add token_4321
assert len(bumper.user_get_tokens("testuser")) == 2 # Test 2 tokens are available
bumper.user_revoke_all_tokens("testuser") # Revoke all tokens
assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available
db = TinyDB("tests/tmp.db")
tokens = db.table("tokens")
tokens.insert(
{
"userid": "testuser",
"token": "token_1234",
"expiration": "{}".format(datetime.now() + timedelta(seconds=-10)),
}
) # Add expired token
db.close()
assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available
bumper.user_revoke_expired_tokens("testuser") # Revoke expired tokens
assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available
db = TinyDB("tests/tmp.db")
tokens = db.table("tokens")
tokens.insert(
{
"userid": "testuser",
"token": "token_1234",
"expiration": "{}".format(datetime.now() + timedelta(seconds=-10)),
}
) # Add expired token
db.close()
assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available
bumper.revoke_expired_tokens() # Revoke expired tokens
assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available
def test_bot_db():
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.bot_add("sn_123", "did_123", "dev_123", "res_123", "co_123")
assert bumper.bot_get("did_123") # Test that bot was added to db
bumper.bot_set_nick("did_123", "nick_123")
assert (
bumper.bot_get("did_123")["nick"] == "nick_123"
) # Test that nick was added to bot
bumper.bot_set_mqtt("did_123", True)
assert bumper.bot_get("did_123")[
"mqtt_connection"
] # Test that mqtt was set True for bot
bumper.bot_set_xmpp("did_123", True)
assert bumper.bot_get("did_123")[
"xmpp_connection"
] # Test that xmpp was set True for bot
bumper.bot_remove("did_123")
assert bumper.bot_get("did_123") == None # Test that bot is no longer in db
def test_client_db():
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.client_add("user_123", "realm_123", "resource_123")
assert bumper.client_get("resource_123") # Test client was added
bumper.client_set_mqtt("resource_123", True)
assert bumper.client_get("resource_123")[
"mqtt_connection"
] # Test that mqtt was set True for client
bumper.client_set_xmpp("resource_123", False)
assert (
bumper.client_get("resource_123")["xmpp_connection"] == False
) # Test that xmpp was set False for client
assert (
len(bumper.get_disconnected_xmpp_clients()) == 1
) # Test len of connected xmpp clients is 1

View file

@ -5,29 +5,18 @@ from tinydb.storages import MemoryStorage
from tinydb import TinyDB, Query from tinydb import TinyDB, Query
import bumper import bumper
import os import os
import datetime, time
import platform import platform
import json import json
import asyncio import asyncio
from testfixtures import LogCapture from testfixtures import LogCapture
def test_get_milli_time():
assert (
bumper.get_milli_time(
datetime.datetime(
2018, 1, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc
).timestamp()
)
== 1514768400000
)
def test_strtobool(): def test_strtobool():
assert bumper.strtobool("t") == True assert bumper.strtobool("t") == True
assert bumper.strtobool("f") == False assert bumper.strtobool("f") == False
assert bumper.strtobool(0) == False assert bumper.strtobool(0) == False
async def test_start_stop(): async def test_start_stop():
with LogCapture() as l: with LogCapture() as l:
if os.path.exists("tests/tmp.db"): if os.path.exists("tests/tmp.db"):
@ -71,142 +60,3 @@ async def test_start_stop_debug():
) )
assert b.shutting_down == True assert b.shutting_down == True
def test_db_path():
bumper.db = None
assert bumper.db_file() == os.path.join(bumper.data_dir, "bumper.db")
def test_user_db():
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.user_add("testuser") # Add testuser
assert (
bumper.user_get("testuser")["userid"] == "testuser"
) # Test that testuser was created and returned
bumper.user_add_device("testuser", "dev_1234") # Add device to testuser
assert (
bumper.user_by_deviceid("dev_1234")["userid"] == "testuser"
) # Test that testuser was found by deviceid
bumper.user_remove_device("testuser", "dev_1234") # Remove device from testuser
assert "dev_1234" not in bumper.user_get("testuser")["devices"]
# Test that dev_1234 was not found in testuser devices
bumper.user_add_bot("testuser", "bot_1234") # Add bot did to testuser
assert "bot_1234" in bumper.user_get("testuser")["bots"]
# Test that bot was found in testuser's bot list
bumper.user_remove_bot("testuser", "bot_1234") # Remove bot did from testuser
assert "bot_1234" not in bumper.user_get("testuser")["bots"]
# Test that bot was not found in testuser's bot list
bumper.user_add_token("testuser", "token_1234") # Add token to testuser
assert bumper.check_token("testuser", "token_1234")
# Test that token was found for testuser
assert bumper.user_get_token("testuser", "token_1234")
# Test that token was returned for testuser
bumper.user_add_authcode(
"testuser", "token_1234", "auth_1234"
) # Add authcode to token_1234 for testuser
assert bumper.check_authcode("testuser", "auth_1234")
# Test that authcode was found for testuser
bumper.user_revoke_authcode(
"testuser", "token_1234", "auth_1234"
) # Remove authcode from testuser
assert bumper.check_authcode("testuser", "auth_1234") == False
# Test that authcode was not found for testuser
bumper.user_revoke_token("testuser", "token_1234") # Remove token from testuser
assert (
bumper.check_token("testuser", "token_1234") == False
) # Test that token was not found for testuser
bumper.user_add_token("testuser", "token_1234") # Add token_1234
bumper.user_add_token("testuser", "token_4321") # Add token_4321
assert len(bumper.user_get_tokens("testuser")) == 2 # Test 2 tokens are available
bumper.user_revoke_all_tokens("testuser") # Revoke all tokens
assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available
db = TinyDB("tests/tmp.db")
tokens = db.table("tokens")
tokens.insert(
{
"userid": "testuser",
"token": "token_1234",
"expiration": "{}".format(
datetime.datetime.now() + datetime.timedelta(seconds=-10)
),
}
) # Add expired token
db.close()
assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available
bumper.user_revoke_expired_tokens("testuser") # Revoke expired tokens
assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available
db = TinyDB("tests/tmp.db")
tokens = db.table("tokens")
tokens.insert(
{
"userid": "testuser",
"token": "token_1234",
"expiration": "{}".format(
datetime.datetime.now() + datetime.timedelta(seconds=-10)
),
}
) # Add expired token
db.close()
assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available
bumper.revoke_expired_tokens() # Revoke expired tokens
assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available
def test_bot_db():
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.bot_add("sn_123", "did_123", "dev_123", "res_123", "co_123")
assert bumper.bot_get("did_123") # Test that bot was added to db
bumper.bot_set_nick("did_123", "nick_123")
assert (
bumper.bot_get("did_123")["nick"] == "nick_123"
) # Test that nick was added to bot
bumper.bot_set_mqtt("did_123", True)
assert bumper.bot_get("did_123")[
"mqtt_connection"
] # Test that mqtt was set True for bot
bumper.bot_set_xmpp("did_123", True)
assert bumper.bot_get("did_123")[
"xmpp_connection"
] # Test that xmpp was set True for bot
bumper.bot_remove("did_123")
assert bumper.bot_get("did_123") == None # Test that bot is no longer in db
def test_client_db():
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.client_add("user_123", "realm_123", "resource_123")
assert bumper.client_get("resource_123") # Test client was added
bumper.client_set_mqtt("resource_123", True)
assert bumper.client_get("resource_123")[
"mqtt_connection"
] # Test that mqtt was set True for client
bumper.client_set_xmpp("resource_123", False)
assert (
bumper.client_get("resource_123")["xmpp_connection"] == False
) # Test that xmpp was set False for client
assert (
len(bumper.get_disconnected_xmpp_clients()) == 1
) # Test len of connected xmpp clients is 1

View file

@ -14,11 +14,12 @@ import time
async def test_helperbot_message(): async def test_helperbot_message():
with LogCapture("helperbot") as l:
mqtt_address = ("127.0.0.1", 8883) mqtt_address = ("127.0.0.1", 8883)
mqtt_server = bumper.MQTTServer(mqtt_address) mqtt_server = bumper.MQTTServer(mqtt_address)
await mqtt_server.broker_coro() await mqtt_server.broker_coro()
with LogCapture() as l:
# Test broadcast message # Test broadcast message
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
await mqtt_helperbot.start_helper_bot() await mqtt_helperbot.start_helper_bot()
@ -125,20 +126,42 @@ async def test_helperbot_message():
) # Check received message was logged ) # Check received message was logged
l.clear() l.clear()
mqtt_helperbot.Client.disconnect() mqtt_helperbot.Client.disconnect()
# Received error message
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
await mqtt_helperbot.start_helper_bot()
assert (
mqtt_helperbot.Client._connected_state._value == True
) # Check helperbot is connected
msg_payload = "<ctl ts='1560904925396' td='errors' old='' new='110'/>"
msg_topic_name = "iot/atr/errors/bot_serial/ls1ok3/wC3g/x"
await mqtt_helperbot.Client.publish(
msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0
)
try:
await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1)
except asyncio.TimeoutError:
pass
l.check_present(
(
"boterror",
"ERROR",
"Received Error - Topic: iot/atr/errors/bot_serial/ls1ok3/wC3g/x - Message: <ctl ts='1560904925396' td='errors' old='' new='110'/>",
)
) # Check received message was logged
l.clear()
mqtt_helperbot.Client.disconnect()
await mqtt_server.broker.shutdown() await mqtt_server.broker.shutdown()
async def test_helperbot_expire_message(): async def test_helperbot_expire_message():
with LogCapture("helperbot") as l:
mqtt_address = ("127.0.0.1", 8883) mqtt_address = ("127.0.0.1", 8883)
mqtt_server = bumper.MQTTServer(mqtt_address) mqtt_server = bumper.MQTTServer(mqtt_address)
await mqtt_server.broker_coro() await mqtt_server.broker_coro()
# mqtt_address = ("127.0.0.1", 8883)
# mqtt_server = bumper.MQTTServer(mqtt_address) with LogCapture("helperbot") as l:
# broker = hbmqtt.broker.Broker(
# mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins"
# )
# await broker.start()
# Test broadcast message # Test broadcast message
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
@ -195,6 +218,7 @@ async def test_helperbot_expire_message():
) )
) # Check received message was logged ) # Check received message was logged
mqtt_helperbot.Client.disconnect() mqtt_helperbot.Client.disconnect()
await mqtt_server.broker.shutdown() await mqtt_server.broker.shutdown()
@ -202,12 +226,6 @@ async def test_helperbot_sendcommand():
mqtt_address = ("127.0.0.1", 8883) mqtt_address = ("127.0.0.1", 8883)
mqtt_server = bumper.MQTTServer(mqtt_address) mqtt_server = bumper.MQTTServer(mqtt_address)
await mqtt_server.broker_coro() await mqtt_server.broker_coro()
# mqtt_address = ("127.0.0.1", 8883)
# mqtt_server = bumper.MQTTServer(mqtt_address)
# broker = hbmqtt.broker.Broker(
# mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins"
# )
# await broker.start()
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
await mqtt_helperbot.start_helper_bot() await mqtt_helperbot.start_helper_bot()

View file

@ -21,11 +21,12 @@ def mock_transport_extra_info(*args, **kwargs):
async def test_xmpp_server(): async def test_xmpp_server():
with LogCapture("xmppserver") as l:
xmpp_address = ("127.0.0.1", 5223) xmpp_address = ("127.0.0.1", 5223)
xmpp_server = bumper.XMPPServer(xmpp_address) xmpp_server = bumper.XMPPServer(xmpp_address)
await xmpp_server.start_async_server() await xmpp_server.start_async_server()
with LogCapture("xmppserver") as l:
reader, writer = await asyncio.open_connection("127.0.0.1", 5223) reader, writer = await asyncio.open_connection("127.0.0.1", 5223)
writer.write(b"<stream:stream />") # Start stream writer.write(b"<stream:stream />") # Start stream
@ -52,10 +53,8 @@ async def test_xmpp_server():
await writer.drain() await writer.drain()
await asyncio.sleep(0.1) await asyncio.sleep(0.1)
xmpp_server.disconnect() xmpp_server.disconnect()
await asyncio.sleep(0.1)
assert len(xmpp_server.clients) == 0 # Client count decreased
print(l)
async def test_client_connect_no_starttls(*args, **kwargs): async def test_client_connect_no_starttls(*args, **kwargs):
@ -209,6 +208,11 @@ async def test_client_connect_starttls_called(*args, **kwargs):
async def test_xmpp_server_client_tls(): async def test_xmpp_server_client_tls():
xmpp_address = ("127.0.0.1", 5223)
xmpp_server = bumper.XMPPServer(xmpp_address)
await xmpp_server.start_async_server()
with LogCapture("xmppserver") as l: with LogCapture("xmppserver") as l:
async def do_stuff_after_start_tls( async def do_stuff_after_start_tls(
@ -227,10 +231,6 @@ async def test_xmpp_server_client_tls():
await writer.drain() await writer.drain()
xmpp_address = ("127.0.0.1", 5223)
xmpp_server = bumper.XMPPServer(xmpp_address)
await xmpp_server.start_async_server()
reader, writer = await asyncio.open_connection("127.0.0.1", 5223) reader, writer = await asyncio.open_connection("127.0.0.1", 5223)
writer.write( writer.write(
@ -616,3 +616,30 @@ async def test_client_send_iq(*args, **kwargs):
# Reset mock calls # Reset mock calls
mock_send.reset_mock() mock_send.reset_mock()
# Bot error report
test_data = "<iq to='fuid_tmpuser@ecouser.net/IOSF53D07BA' type='set' id='631'><query xmlns='com:ctl'><ctl td='error' errs='102'/></query></iq>".encode(
"utf-8"
)
xmppclient2._parse_data(test_data)
assert (
mock_send.mock_calls[0].args[0]
== '<iq from="E0000000000000001234@159.ecorobot.net/atom" id="631" to="fuid_tmpuser@ecouser.net/IOSF53D07BA" type="set"><query xmlns="com:ctl"><ctl errs="102" td="error" /></query></iq>'
) # result sent to ecouser.net
# Reset mock calls
mock_send.reset_mock()
# Bot "DorpError" to all
test_data = "<iq to='rl.ecorobot.net' type='set' id='1234'><query xmlns='com:sf'><sf td='pub' t='log' ts='1559893796000' tp='p' k='DeviceAlert' v='DorpError' f='E0000000000000001234@159.ecorobot.net' g='fuid_tmpuser@ecouser.net'/></query></iq>".encode(
"utf-8"
)
xmppclient2._parse_data(test_data)
assert (
mock_send.mock_calls[0].args[0]
== '<iq xmlns="com:sf" from="E0000000000000001234@159.ecorobot.net/atom" id="1234" to="rl.ecorobot.net" type="set"><query xmlns="com:ctl"><sf f="E0000000000000001234@159.ecorobot.net" g="fuid_tmpuser@ecouser.net" k="DeviceAlert" t="log" td="pub" tp="p" ts="1559893796000" v="DorpError" /></query></iq>'
) # result sent to ecouser.net
# Reset mock calls
mock_send.reset_mock()

View file

@ -100,4 +100,3 @@ def test_main(mock_firstrun):
bumper.main() bumper.main()
assert mock_firstrun.called == True assert mock_firstrun.called == True
bumper.ca_cert = "tests/test_certs/ca.crt" bumper.ca_cert = "tests/test_certs/ca.crt"