Merge pull request #29 from bmartin5692/support-ecovacs-home

Support ecovacs home app
This commit is contained in:
Brian Martin 2019-05-20 22:16:47 -04:00 committed by GitHub
commit 8c5f603e15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 936 additions and 50 deletions

View file

@ -6,6 +6,7 @@ from .mqttserver import MQTTHelperBot
from .xmppserver import XMPPServer from .xmppserver import XMPPServer
import asyncio import asyncio
import contextvars import contextvars
import json
import time import time
from datetime import datetime, timedelta from datetime import datetime, timedelta
import platform import platform
@ -249,6 +250,299 @@ class VacBotDevice(object):
"xmpp_connection": self.xmpp_connection, "xmpp_connection": self.xmpp_connection,
} }
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=False)#, indent=4)
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): class VacBotClient(object):
def __init__(self, userid="", realm="", token=""): def __init__(self, userid="", realm="", token=""):
@ -289,6 +583,21 @@ def check_authcode(uid, authcode):
return False 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): def check_token(uid, token):
bumperlog.debug("Checking for token: {}".format(token)) bumperlog.debug("Checking for token: {}".format(token))
@ -342,6 +651,16 @@ def bot_get(did):
return bots.get(Bot.did == did) 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): def bot_full_upsert(vacbot):
bots = db_get().table("bots") bots = db_get().table("bots")
Bot = Query() Bot = Query()

View file

@ -11,6 +11,7 @@ import asyncio
import contextvars import contextvars
from aiohttp import web from aiohttp import web
import uuid import uuid
import xml.etree.ElementTree as ET
class aiohttp_filter(logging.Filter): class aiohttp_filter(logging.Filter):
@ -35,6 +36,21 @@ confserverlog = logging.getLogger("confserver")
logging.getLogger("asyncio").setLevel(logging.CRITICAL + 1) # Ignore this logger logging.getLogger("asyncio").setLevel(logging.CRITICAL + 1) # Ignore this logger
logging.getLogger("aiohttp.access").addFilter(aiohttp_filter()) logging.getLogger("aiohttp.access").addFilter(aiohttp_filter())
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):
@ -95,6 +111,10 @@ class ConfServer:
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/checkLogin", "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/checkLogin",
self.handle_login, self.handle_login,
), ),
web.get( #EcoVacs Home GetUserAccountInfo
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/getUserAccountInfo",
self.handle_getUserAccountInfo,
),
web.get( web.get(
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/logout", "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/logout",
self.handle_logout, self.handle_logout,
@ -103,24 +123,72 @@ class ConfServer:
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/getAuthCode", "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/getAuthCode",
self.handle_getAuthCode, self.handle_getAuthCode,
), ),
web.get( #EcoVacs Home GetAuthCode
"/{apiversion}/{apptype}/auth/getAuthCode",
self.handle_getAuthCode
),
web.get( web.get(
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/checkAgreement", "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/checkAgreement",
self.handle_checkAgreement, self.handle_checkAgreement,
), ),
web.get( #EcoVacs Home CheckAgreement
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/checkAgreementBatch",
self.handle_checkAgreement,
),
web.get( web.get(
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/checkVersion", "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/checkVersion",
self.handle_checkVersion, self.handle_checkVersion,
), ),
web.get( #EcoVacs Home CheckAPPVersion
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/checkAPPVersion",
self.handle_checkAPPVersion,
),
web.get( #EcoVacs Home Upload Device Info
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/uploadDeviceInfo",
self.handle_uploadDeviceInfo,
),
web.get( #EcoVacs Home GetAdByPositionType
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/ad/getAdByPositionType",
self.handle_getAdByPositionType,
),
web.get( #EcoVacs Home Get Boot Screen
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/ad/getBootScreen",
self.handle_getBootScreen,
),
web.get( #EcoVacs Home message hasUnreadMsg
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/message/hasUnreadMsg",
self.handle_hasUnreadMessage,
),
web.get( #EcoVacs Home neng message hasUnreadMsg
"/api/neng/message/hasUnreadMsg",
self.handle_neng_hasUnreadMessage,
),
web.get( #EcoVacs Home message getMsgList
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/message/getMsgList",
self.handle_getMsgList,
),
web.get( #EcoVacs Home common getSystemReminder
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/getSystemReminder",
self.handle_getSystemReminder,
),
web.get( #EcoVacs Home shop getCnWapShopConfig
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/shop/getCnWapShopConfig",
self.handle_getCnWapShopConfig,
),
web.get( web.get(
"/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/campaign/homePageAlert", "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/campaign/homePageAlert",
self.handle_homePageAlert, self.handle_homePageAlert,
), ),
web.post("/api/users/user.do", self.handle_usersapi), web.post("/api/users/user.do", self.handle_usersapi),
web.get("/api/users/user.do", self.handle_usersapi), web.get("/api/users/user.do", self.handle_usersapi),
web.post("/api/appsvr/app.do", self.handle_appsvr_api), #EcoVacs Home
web.get("/api/appsvr/app.do", self.handle_appsvr_api), #EcoVacs Home
web.post( web.post(
"/api/pim/product/getProductIotMap", self.handle_getProductIotMap "/api/pim/product/getProductIotMap", self.handle_getProductIotMap
), ),
web.post("/api/lg/log.do", self.handle_lg_log), #EcoVacs Home
web.post("/api/iot/devmanager.do", self.handle_devmanager_botcommand), web.post("/api/iot/devmanager.do", self.handle_devmanager_botcommand),
web.post("/api/dim/devmanager.do", self.handle_dim_devmanager), #EcoVacs Home
web.post("/lookup.do", self.handle_lookup), web.post("/lookup.do", self.handle_lookup),
] ]
) )
@ -174,6 +242,7 @@ class ConfServer:
try: try:
user_devid = request.match_info.get("devid", "") user_devid = request.match_info.get("devid", "")
countrycode = request.match_info.get("country", "us") countrycode = request.match_info.get("country", "us")
apptype = request.match_info.get("apptype", "")
confserverlog.info( confserverlog.info(
"client with devid {} attempting login".format(user_devid) "client with devid {} attempting login".format(user_devid)
) )
@ -184,28 +253,43 @@ class ConfServer:
user = bumper.user_by_deviceid(user_devid) user = bumper.user_by_deviceid(user_devid)
if "checkLogin" in request.path: if "checkLogin" in request.path:
self.check_token( self.check_token(
countrycode, user, request.query["accessToken"] apptype, countrycode, user, request.query["accessToken"]
) )
else: else:
if "global_" in apptype: #EcoVacs Home
login_details = EcoVacsHome_Login()
login_details.ucUid = "fuid_{}".format(user["userid"])
login_details.loginName = "fusername_{}".format(user["userid"])
login_details.mobile = None
else:
login_details = EcoVacs_Login()
# Deactivate old tokens and authcodes # Deactivate old tokens and authcodes
bumper.user_revoke_expired_tokens(user["userid"]) bumper.user_revoke_expired_tokens(user["userid"])
login_details.accessToken = self.generate_token(user)
login_details.uid = "fuid_{}".format(user["userid"])
login_details.username = "fusername_{}".format(user["userid"])
login_details.country = countrycode
login_details.email = "null@null.com"
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
"data": { "data": json.loads(login_details.toJSON()),
"accessToken": self.generate_token( #{
user # "accessToken": self.generate_token(tmpuser), # Generate a token
), # generate a new token # "country": countrycode,
"country": countrycode, # "email": "null@null.com",
"email": "null@null.com", # "uid": "fuid_{}".format(tmpuser["userid"]),
"uid": "fuid_{}".format(user["userid"]), # "username": "fusername_{}".format(tmpuser["userid"]),
"username": "fusername_{}".format(user["userid"]), #},
},
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time( "time": bumper.get_milli_time(
datetime.utcnow().timestamp() datetime.utcnow().timestamp()
), ),
} }
return web.json_response(body) return web.json_response(body)
body = { body = {
@ -219,28 +303,86 @@ class ConfServer:
else: else:
return web.json_response( return web.json_response(
self._auth_any(user_devid, countrycode, request) self._auth_any(user_devid, apptype, countrycode, request)
) )
except Exception as e: except Exception as e:
confserverlog.exception("{}".format(e)) confserverlog.exception("{}".format(e))
def check_token(self, countrycode, user, token): def handle_getUserAccountInfo(self, request):
if bumper.check_token(user["userid"], token): try:
user_devid = request.match_info.get("devid", "")
countrycode = request.match_info.get("country", "us")
apptype = request.match_info.get("apptype", "")
user = bumper.user_by_deviceid(user_devid)
if "global_" in apptype: #EcoVacs Home
login_details = EcoVacsHome_Login()
login_details.ucUid = "fuid_{}".format(user["userid"])
login_details.loginName = "fusername_{}".format(user["userid"])
login_details.mobile = None
else:
login_details = EcoVacs_Login()
login_details.uid = "fuid_{}".format(user["userid"])
login_details.username = "fusername_{}".format(user["userid"])
login_details.country = countrycode
login_details.email = "null@null.com"
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
"data": { "data":
"accessToken": token, {
"country": countrycode, "email": login_details.email,
"email": "null@null.com", "hasMobile": "N",
"uid": "fuid_{}".format(user["userid"]), "hasPassword": "Y",
"username": "fusername_{}".format(user["userid"]), "uid": login_details.uid,
"userName": login_details.username,
"obfuscatedMobile": None,
"mobile": None,
"loginName": login_details.loginName
}, },
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": bumper.get_milli_time(datetime.utcnow().timestamp()),
} }
return web.json_response(body) return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
def check_token(self, apptype, countrycode, user, token):
if bumper.check_token(user["userid"], token):
if "global_" in apptype: #EcoVacs Home
login_details = EcoVacsHome_Login()
login_details.ucUid = "fuid_{}".format(user["userid"])
login_details.loginName = "fusername_{}".format(user["userid"])
login_details.mobile = None
else:
login_details = EcoVacs_Login()
login_details.accessToken = token
login_details.uid = "fuid_{}".format(user["userid"])
login_details.username = "fusername_{}".format(user["userid"])
login_details.country = countrycode
login_details.email = "null@null.com"
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": json.loads(login_details.toJSON()),
#{
# "accessToken": self.generate_token(tmpuser), # Generate a token
# "country": countrycode,
# "email": "null@null.com",
# "uid": "fuid_{}".format(tmpuser["userid"]),
# "username": "fusername_{}".format(tmpuser["userid"]),
#},
"msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
else: else:
body = { body = {
"code": bumper.ERR_TOKEN_INVALID, "code": bumper.ERR_TOKEN_INVALID,
@ -260,7 +402,7 @@ class ConfServer:
bumper.user_add_authcode(user["userid"], token, tmpauthcode) bumper.user_add_authcode(user["userid"], token, tmpauthcode)
return tmpauthcode return tmpauthcode
def _auth_any(self, devid, country, request): def _auth_any(self, devid, apptype, country, request):
try: try:
user_devid = devid user_devid = devid
countrycode = country countrycode = country
@ -269,10 +411,36 @@ class ConfServer:
if user: # Default to user 0 if user: # Default to user 0
tmpuser = user tmpuser = user
if "global_" in apptype: #EcoVacs Home
login_details = EcoVacsHome_Login()
login_details.ucUid = "fuid_{}".format(tmpuser["userid"])
login_details.loginName = "fusername_{}".format(tmpuser["userid"])
login_details.mobile = None
else:
login_details = EcoVacs_Login()
login_details.accessToken = self.generate_token(tmpuser)
login_details.uid = "fuid_{}".format(tmpuser["userid"])
login_details.username = "fusername_{}".format(tmpuser["userid"])
login_details.country = countrycode
login_details.email = "null@null.com"
bumper.user_add_device(tmpuser["userid"], user_devid) bumper.user_add_device(tmpuser["userid"], user_devid)
else: else:
bumper.user_add("tmpuser") # Add a new user bumper.user_add("tmpuser") # Add a new user
tmpuser = bumper.user_get("tmpuser") tmpuser = bumper.user_get("tmpuser")
if "global_" in apptype: #EcoVacs Home
login_details = EcoVacsHome_Login()
login_details.ucUid = "fuid_{}".format(tmpuser["userid"])
login_details.loginName = "fusername_{}".format(tmpuser["userid"])
login_details.mobile = None
else:
login_details = EcoVacs_Login()
login_details.accessToken = self.generate_token(tmpuser)
login_details.uid = "fuid_{}".format(tmpuser["userid"])
login_details.username = "fusername_{}".format(tmpuser["userid"])
login_details.country = countrycode
login_details.email = "null@null.com"
bumper.user_add_device(tmpuser["userid"], user_devid) bumper.user_add_device(tmpuser["userid"], user_devid)
for bot in bots: # Add all bots to the user for bot in bots: # Add all bots to the user
@ -280,7 +448,7 @@ class ConfServer:
if "checkLogin" in request.path: # If request was to check a token do so if "checkLogin" in request.path: # If request was to check a token do so
checkToken = self.check_token( checkToken = self.check_token(
countrycode, tmpuser, request.query["accessToken"] apptype, countrycode, tmpuser, request.query["accessToken"]
) )
isGood = json.loads(checkToken.text) isGood = json.loads(checkToken.text)
if isGood["code"] == "0000": if isGood["code"] == "0000":
@ -289,15 +457,17 @@ class ConfServer:
# Deactivate old tokens and authcodes # Deactivate old tokens and authcodes
bumper.user_revoke_expired_tokens(tmpuser["userid"]) bumper.user_revoke_expired_tokens(tmpuser["userid"])
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
"data": { "data": json.loads(login_details.toJSON()),
"accessToken": self.generate_token(tmpuser), # Generate a token #{
"country": countrycode, # "accessToken": self.generate_token(tmpuser), # Generate a token
"email": "null@null.com", # "country": countrycode,
"uid": "fuid_{}".format(tmpuser["userid"]), # "email": "null@null.com",
"username": "fusername_{}".format(tmpuser["userid"]), # "uid": "fuid_{}".format(tmpuser["userid"]),
}, # "username": "fusername_{}".format(tmpuser["userid"]),
#},
"msg": "操作成功", "msg": "操作成功",
"time": bumper.get_milli_time(datetime.utcnow().timestamp()), "time": bumper.get_milli_time(datetime.utcnow().timestamp()),
} }
@ -333,11 +503,16 @@ class ConfServer:
async def handle_getAuthCode(self, request): async def handle_getAuthCode(self, request):
try: try:
apptype = request.match_info.get("apptype", "")
user_devid = request.match_info.get("devid", "") #Ecovacs
if user_devid == "":
user_devid = request.query["deviceId"] #Ecovacs Home
user_devid = request.match_info.get("devid", "")
if not user_devid == "": if not user_devid == "":
user = bumper.user_by_deviceid(user_devid) user = bumper.user_by_deviceid(user_devid)
token = ""
if user: if user:
if "accessToken" in request.query:
token = bumper.user_get_token( token = bumper.user_get_token(
user["userid"], request.query["accessToken"] user["userid"], request.query["accessToken"]
) )
@ -351,7 +526,20 @@ class ConfServer:
) )
else: else:
authcode = token["authcode"] authcode = token["authcode"]
if "global" in apptype:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": {
"authCode": authcode,
"ecovacsUid": request.query["uid"],
},
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(
datetime.utcnow().timestamp()
),
}
else:
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
"data": { "data": {
@ -399,8 +587,197 @@ class ConfServer:
except Exception as e: except Exception as e:
confserverlog.exception("{}".format(e)) confserverlog.exception("{}".format(e))
async def handle_checkAPPVersion(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": {
"c": None,
"downPageUrl": None,
"img": None,
"nextAlertTime": None,
"r": 0,
"t": None,
"u": None,
"ut": 0,
"v": None,
},
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_uploadDeviceInfo(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": None,
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_getAdByPositionType(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": None,
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_getBootScreen(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": None,
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_hasUnreadMessage(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": "N",
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_neng_hasUnreadMessage(self, request): #EcoVacs Home
try:
body = {
"code": 0,
"data": {
"hasUnRead": True
},
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_getMsgList(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": {
"hasNextPage": 0,
"items": []
},
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_getCnWapShopConfig(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": {
"myShopShowFlag": "N",
"myShopUrl": "",
"shopIndexShowFlag": "N",
"shopIndexUrl": ""
},
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_getSystemReminder(self, request): #EcoVacs Home
try:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data":
{
"iosGradeTime": {
"iodGradeFlag": "N"
},
"openNotification": {
"openNotificationContent": None,
"openNotificationFlag": "N",
"openNotificationTitle": None
}
},
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_checkAgreement(self, request): async def handle_checkAgreement(self, request):
try: try:
apptype = request.match_info.get("apptype", "")
if "global_" in apptype:
body = {
"code": bumper.RETURN_API_SUCCESS,
"data": [
{
"force": "N",
"id": "20180804040641_7d746faf18b8cb22a50d145598fe4c90",
"type": "USER",
"url": "https://bumper.ecovacs.com/content/agreement?id=20180804040641_7d746faf18b8cb22a50d145598fe4c90&language=EN", #"https://gl-us-wap.ecovacs.com/content/agreement?id=20180804040641_7d746faf18b8cb22a50d145598fe4c90&language=EN
"version": "1.01"
},
{
"force": "N",
"id": "20180804040245_4e7c56dfb7ebd3b81b1f2747d0859fac",
"type": "PRIVACY",
"url": "https://bumper.ecovacs.com/content/agreement?id=20180804040245_4e7c56dfb7ebd3b81b1f2747d0859fac&language=EN", #"https://gl-us-wap.ecovacs.com/content/agreement?id=20180804040245_4e7c56dfb7ebd3b81b1f2747d0859fac&language=EN"
"version": "1.01"
}
],
"msg": "操作成功",
"success": True,
"time": bumper.get_milli_time(datetime.utcnow().timestamp()),
}
else:
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
"data": [], "data": [],
@ -439,6 +816,7 @@ class ConfServer:
confserverlog.exception("{}".format(e)) confserverlog.exception("{}".format(e))
async def handle_getProductIotMap(self, request): async def handle_getProductIotMap(self, request):
user_devid = request.match_info.get("devid", "")
try: try:
body = { body = {
"code": bumper.RETURN_API_SUCCESS, "code": bumper.RETURN_API_SUCCESS,
@ -541,6 +919,7 @@ class ConfServer:
body = {"result": "ok", "ip": "47.88.66.164", "port": 8005} body = {"result": "ok", "ip": "47.88.66.164", "port": 8005}
elif todo == "loginByItToken": elif todo == "loginByItToken":
if "userId" in postbody:
if bumper.check_authcode(postbody["userId"], postbody["token"]): if bumper.check_authcode(postbody["userId"], postbody["token"]):
body = { body = {
"resource": postbody["resource"], "resource": postbody["resource"],
@ -549,6 +928,19 @@ class ConfServer:
"token": postbody["token"], "token": postbody["token"],
"userId": postbody["userId"], "userId": postbody["userId"],
} }
else: #EcoVacs Home LoginByITToken
loginToken = bumper.loginByItToken(postbody["token"])
if not loginToken == {}:
body = {
"resource": postbody["resource"],
"result": "ok",
"todo": "result",
"token": loginToken["token"],
"userId": loginToken["userid"],
}
else:
body = {"result": "fail", "todo": "result"}
elif todo == "GetDeviceList": elif todo == "GetDeviceList":
body = { body = {
@ -582,6 +974,51 @@ class ConfServer:
body = {"result": "fail", "todo": "result"} body = {"result": "fail", "todo": "result"}
return web.json_response(body) return web.json_response(body)
async def handle_appsvr_api(self, request):
if not request.method == "GET": # Skip GET for now
try:
body = {}
postbody = {}
if request.content_type == "application/x-www-form-urlencoded":
postbody = await request.post()
else:
postbody = json.loads(await request.text())
todo = postbody["todo"]
if todo == "GetGlobalDeviceList": #EcoVacs Home
bots = bumper.db_get().table("bots").all()
botlist = []
for bot in bots:
if bot["class"] != "":
b = bumper.bot_toEcoVacsHome_JSON(bot)
botlist.append(json.loads(b))
body = {
"code": 0,
"devices": botlist,
"ret": "ok",
"todo": "result",
}
confserverlog.debug(
"\r\n POST: {} \r\n Response: {}".format(postbody, body)
)
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
# Return fail for GET
body = {"result": "fail", "todo": "result"}
return web.json_response(body)
async def handle_lookup(self, request): async def handle_lookup(self, request):
try: try:
@ -623,14 +1060,96 @@ class ConfServer:
except Exception as e: except Exception as e:
confserverlog.exception("{}".format(e)) confserverlog.exception("{}".format(e))
async def handle_lg_log(self, request): #EcoVacs Home
try:
json_body = json.loads(await request.text())
randomid = "".join(random.sample(string.ascii_letters, 6))
did = json_body["did"]
botdetails = bumper.bot_get(did)
if botdetails:
if not "cmdName" in json_body:
if "td" in json_body:
json_body["cmdName"] = json_body["td"]
#json_body["td"] = "q"
if not "toId" in json_body:
json_body["toId"] = did
if not "toType" in json_body:
json_body["toType"] = botdetails["class"]
if not "toRes" in json_body:
json_body["toRes"] = botdetails["resource"]
if not "payloadType" in json_body:
json_body["payloadType"] = "x"
if not "payload" in json_body:
json_body["payload"] = ""
if json_body["td"] == "GetCleanLogs":
json_body["td"] = "q"
json_body["payload"] = '<ctl count=\"30\"/>' #<ctl />"
if did != "":
confserverlog.debug("BotCommand: {}".format(json_body))
bot = bumper.bot_get(did)
if bot["company"] == "eco-ng" and bot["mqtt_connection"] == True:
body = ""
retcmd = await self.helperbot.send_command(json_body, randomid)
logs = []
logsroot = ET.fromstring(retcmd["resp"])
if logsroot.attrib["ret"] == "ok":
cleanlogs = logsroot.getchildren()
for l in cleanlogs:
logs.append(l.attrib)
body = {
"ret": "ok",
#"logs": logs, #TODO: Doesn't parse correctly, new protocol & server side processing
"logs": []
}
else:
body = {
"ret": "ok",
"logs": [],
}
confserverlog.debug(
"\r\n POST: {} \r\n Response: {}".format(json_body, body)
)
return web.json_response(body)
else:
# No response, send error back
confserverlog.error(
"No bots with DID: {} connected to MQTT".format(
json_body["toId"]
)
)
body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_devmanager_botcommand(self, request): async def handle_devmanager_botcommand(self, request):
try: try:
json_body = json.loads(await request.text()) json_body = json.loads(await request.text())
confserverlog.debug("BotCommand: {}".format(json_body))
randomid = "".join(random.sample(string.ascii_letters, 6))
randomid = "".join(random.sample(string.ascii_letters, 6))
did = ""
if "toId" in json_body: # Its a command if "toId" in json_body: # Its a command
bot = bumper.bot_get(json_body["toId"]) did = json_body["toId"]
if did != "":
confserverlog.debug("BotCommand: {}".format(json_body))
bot = bumper.bot_get(did)
if bot["company"] == "eco-ng" and bot["mqtt_connection"] == True: if bot["company"] == "eco-ng" and bot["mqtt_connection"] == True:
retcmd = await self.helperbot.send_command(json_body, randomid) retcmd = await self.helperbot.send_command(json_body, randomid)
body = retcmd body = retcmd
@ -647,12 +1166,60 @@ class ConfServer:
) )
body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"} body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"}
return web.json_response(body) return web.json_response(body)
else: else:
if "td" in json_body: # Seen when doing initial wifi config if "td" in json_body: # Seen when doing initial wifi config
if json_body["td"] == "PollSCResult": if json_body["td"] == "PollSCResult":
body = {"ret": "ok"} body = {"ret": "ok"}
return web.json_response(body) return web.json_response(body)
if json_body["td"] == "HasUnreadMsg": #EcoVacs Home
body = {"ret":"ok","unRead":False}
return web.json_response(body)
except Exception as e:
confserverlog.exception("{}".format(e))
async def handle_dim_devmanager(self, request):
try:
json_body = json.loads(await request.text())
randomid = "".join(random.sample(string.ascii_letters, 6))
did = ""
if "toId" in json_body: # Its a command
did = json_body["toId"]
if did != "":
confserverlog.debug("BotCommand: {}".format(json_body))
bot = bumper.bot_get(did)
if bot["company"] == "eco-ng" and bot["mqtt_connection"] == True:
retcmd = await self.helperbot.send_command(json_body, randomid)
body = retcmd
confserverlog.debug(
"\r\n POST: {} \r\n Response: {}".format(json_body, body)
)
return web.json_response(body)
else:
# No response, send error back
confserverlog.error(
"No bots with DID: {} connected to MQTT".format(
json_body["toId"]
)
)
body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"}
return web.json_response(body)
else:
if "td" in json_body: # Seen when doing initial wifi config
if json_body["td"] == "PollSCResult":
body = {"ret": "ok"}
return web.json_response(body)
if json_body["td"] == "HasUnreadMsg": #EcoVacs Home
body = {"ret":"ok","unRead":False}
return web.json_response(body)
except Exception as e: except Exception as e:
confserverlog.exception("{}".format(e)) confserverlog.exception("{}".format(e))