SCLP
This commit is contained in:
323
SCLP/device/call.py
Normal file
323
SCLP/device/call.py
Normal file
@@ -0,0 +1,323 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
"""
|
||||
@Author : xuxingchen
|
||||
@Contact : xuxingchen@sinochem.com
|
||||
@Desc : 由服务主动调用的一些方法,实现调用后自动连接mqtt进行任务下发和回馈处理,解耦服务端与mqtt
|
||||
"""
|
||||
import json
|
||||
import time
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
from config import (BROKER_HOST, BROKER_PORT, BROKER_USERNAME, BROKER_PASSWD, PREFIX_PATH, SUB_PATH,
|
||||
SLEEP_TIME, TIMEOUT_SECOND)
|
||||
from config import APP_HOST as HOST_IP
|
||||
from config import IMAGE_SERVER_PORT as PORT
|
||||
from utils import logger
|
||||
from utils.misc import generate_captcha_text, UserData, create_mqtt_client, on_publish, on_disconnect, now_tz_datetime
|
||||
|
||||
|
||||
class CallMessage:
|
||||
def __init__(self, service_code, params):
|
||||
self.messageId = generate_captcha_text(16)
|
||||
self.version = "1.0"
|
||||
self.time = int(time.time() * 1000)
|
||||
self.fromUid = "system"
|
||||
self.serviceCode = service_code
|
||||
self.params = params
|
||||
|
||||
def dict(self):
|
||||
_dict = self.__dict__.copy()
|
||||
for key, value in self.__dict__.items():
|
||||
if value is None:
|
||||
_dict.pop(key)
|
||||
_dict["from"] = "backend"
|
||||
return _dict
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return json.dumps(self.dict())
|
||||
|
||||
|
||||
class AddFaceItem(BaseModel):
|
||||
name: str
|
||||
user_id: str | int
|
||||
device_ids: str
|
||||
start_date: str = now_tz_datetime()
|
||||
phone_number: str = ""
|
||||
face_url: str
|
||||
expire_date: Optional[str] = "2099-01-01T01:01:01.001Z"
|
||||
|
||||
@field_validator("user_id")
|
||||
def check_user_id(cls, value):
|
||||
if isinstance(value, int):
|
||||
return str(value)
|
||||
return value
|
||||
|
||||
|
||||
class DelFaceItem(BaseModel):
|
||||
user_id: str | int
|
||||
device_ids: str
|
||||
|
||||
@field_validator("user_id")
|
||||
def check_user_id(cls, value):
|
||||
if isinstance(value, int):
|
||||
return str(value)
|
||||
return value
|
||||
|
||||
|
||||
ACTION = {
|
||||
"insert": "新增",
|
||||
"update": "更新",
|
||||
"delete": "删除"
|
||||
}
|
||||
|
||||
|
||||
class VehicleRegistrationItem(BaseModel):
|
||||
car_plate_no: str # 车牌
|
||||
registration_id: str
|
||||
owner_id: str
|
||||
owner_name: str
|
||||
registration_time: str
|
||||
begin_time: str
|
||||
end_time: str = "2099-01-01T01:01:01.001Z"
|
||||
action: str # insert, update, delete
|
||||
registration_type: str # 0: 业主,1: 访客
|
||||
|
||||
|
||||
class UpdateFixedCardItem(BaseModel):
|
||||
vehicle_owner_id: str
|
||||
vehicle_owner_name: str
|
||||
vehicle_owner_phone: str
|
||||
plate_number: str # 车牌
|
||||
effective_date_begin: str
|
||||
effective_date_end: str
|
||||
action: str # insert, update, delete
|
||||
card_id: str # 在新增时进行生成
|
||||
|
||||
|
||||
def on_connect(client, userdata, _flags, rc):
|
||||
logger.Logger.debug(f"🔗 Mqtt connection! {{rc: {rc}}} 🔗")
|
||||
if userdata.topics:
|
||||
_topics = [(topic, 0) for topic in userdata.topics]
|
||||
client.subscribe(_topics)
|
||||
logger.Logger.debug(f"subscribe topics: {userdata.topics}")
|
||||
|
||||
|
||||
def on_message(_client, userdata: UserData, message):
|
||||
try:
|
||||
logger.Logger.debug("💡 接收到新数据,执行 on_message 中 ...", log_path=None)
|
||||
msg = json.loads(message.payload.decode().replace("\x00", ""))
|
||||
logger.Logger.info(f"{message.topic}: {msg}")
|
||||
userdata.set_topic(message.topic)
|
||||
if userdata.token:
|
||||
if "messageId" in msg.keys() and userdata.token == msg["messageId"]: # 兼容aiot平台
|
||||
userdata.set_status_add("status", True)
|
||||
userdata.set_status_add("response", msg)
|
||||
except Exception as e:
|
||||
logger.Logger.error(f"{type(e).__name__}, {e}")
|
||||
if logger.DEBUG:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
class ServicesCall:
|
||||
def __init__(self):
|
||||
# 创建mqtt连接
|
||||
self.userdata = UserData()
|
||||
self.client = create_mqtt_client(BROKER_HOST, BROKER_PORT,
|
||||
self.userdata, on_message, on_publish, on_connect, on_disconnect,
|
||||
username=BROKER_USERNAME, password=BROKER_PASSWD)
|
||||
self.client.loop_start()
|
||||
|
||||
def __del__(self):
|
||||
self.client.loop_stop()
|
||||
|
||||
def add_face(self, device_id, obj: AddFaceItem) -> tuple[bool, int, str]:
|
||||
if obj.face_url.startswith("http"):
|
||||
face_filename = obj.face_url.split('/')[-1]
|
||||
else:
|
||||
face_filename = obj.face_url
|
||||
obj.face_url = f"http://{HOST_IP}:{PORT}{PREFIX_PATH}/{SUB_PATH}/{face_filename}"
|
||||
topic = f"/jmlink/{device_id}/tml/service/call"
|
||||
self.userdata.set_topic(topic)
|
||||
logger.Logger.debug(f"{'=' * 10} 🚩 AddFace 🚩 {'=' * 10}")
|
||||
logger.Logger.debug(f"{obj.device_ids} 添加用户 {obj.user_id} 的人脸授权")
|
||||
cm = CallMessage("add_face", obj.__dict__)
|
||||
self.userdata.set_message(cm.dict())
|
||||
# 等待回传
|
||||
self.userdata.set_token(cm.messageId)
|
||||
self.userdata.set_status_add("status", False)
|
||||
self.userdata.set_status_add("start_timestamp", time.time())
|
||||
topic_resp = f"/jmlink/{device_id}/tml/service/call_resp"
|
||||
self.client.subscribe(topic_resp)
|
||||
self.client.publish(topic, cm())
|
||||
try:
|
||||
while True:
|
||||
if self.userdata.status["status"]:
|
||||
if "code" in self.userdata.status["response"].keys():
|
||||
if self.userdata.status["response"]["code"] != 0:
|
||||
error_code = self.userdata.status['response']['code']
|
||||
logger.Logger.error(
|
||||
f"用户 - {obj.user_id} 在设备 - {device_id} 上人脸下置失败,错误码 {error_code}")
|
||||
return False, error_code, self.userdata.status['response']['message']
|
||||
else:
|
||||
logger.Logger.info(f"设备 - {obj.device_ids} 用户({obj.user_id}) 人脸完成授权")
|
||||
return True, 0, ""
|
||||
if time.time() - self.userdata.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出
|
||||
logger.Logger.error("等待回复超时")
|
||||
return False, -1, "等待回复超时"
|
||||
time.sleep(SLEEP_TIME)
|
||||
finally:
|
||||
self.client.unsubscribe(topic_resp)
|
||||
logger.Logger.debug(f"移除订阅: {topic_resp}")
|
||||
self.userdata.set_token(None)
|
||||
self.userdata.set_status_remove("response")
|
||||
logger.Logger.debug(f"{'=' * 10} 🏁 AddFace 🏁 {'=' * 10}")
|
||||
|
||||
def del_face(self, device_id, obj: DelFaceItem) -> tuple[bool, int, str]:
|
||||
topic = f"/jmlink/{device_id}/tml/service/call"
|
||||
self.userdata.set_topic(topic)
|
||||
logger.Logger.debug(f"{'=' * 10} 🚩 DelFace 🚩 {'=' * 10}")
|
||||
logger.Logger.debug(f"从 {obj.device_ids} 移除用户 {obj.user_id} 的人脸授权")
|
||||
cm = CallMessage("del_face", obj.__dict__)
|
||||
self.userdata.set_message(cm.dict())
|
||||
# 等待回传
|
||||
self.userdata.set_token(cm.messageId)
|
||||
self.userdata.set_status_add("status", False)
|
||||
self.userdata.set_status_add("start_timestamp", time.time())
|
||||
topic_resp = f"/jmlink/{device_id}/tml/service/call_resp"
|
||||
self.client.subscribe(topic_resp)
|
||||
self.client.publish(topic, cm())
|
||||
try:
|
||||
while True:
|
||||
if self.userdata.status["status"]:
|
||||
if "code" in self.userdata.status["response"].keys():
|
||||
if self.userdata.status["response"]["code"] != 0:
|
||||
error_code = self.userdata.status['response']['code']
|
||||
logger.Logger.error(
|
||||
f"用户 - {obj.user_id} 在设备 - {device_id} 上人脸移除失败,错误码 {error_code}")
|
||||
return False, error_code, self.userdata.status['response']['message']
|
||||
else:
|
||||
logger.Logger.info(f"设备 - {obj.device_ids} 用户({obj.user_id}) 人脸完成移除")
|
||||
return True, 0, ""
|
||||
if time.time() - self.userdata.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出
|
||||
logger.Logger.error("等待回复超时")
|
||||
return False, -1, "等待回复超时"
|
||||
time.sleep(SLEEP_TIME)
|
||||
finally:
|
||||
self.client.unsubscribe(topic_resp)
|
||||
logger.Logger.debug(f"移除订阅: {topic_resp}")
|
||||
self.userdata.set_token(None)
|
||||
self.userdata.set_status_remove("response")
|
||||
logger.Logger.debug(f"{'=' * 10} 🏁 DelFace 🏁 {'=' * 10}")
|
||||
|
||||
def vehicle_registration(self, device_id, obj: VehicleRegistrationItem) -> tuple[bool, int, str]:
|
||||
topic = f"/jmlink/{device_id}/tml/service/call"
|
||||
self.userdata.set_topic(topic)
|
||||
logger.Logger.debug(f"{'=' * 10} 🚩 VehicleRegistration 🚩 {'=' * 10}")
|
||||
logger.Logger.debug(f"{device_id} {ACTION[obj.action]}车辆 {obj.car_plate_no} 信息")
|
||||
cm = CallMessage("vehicle_registration", obj.__dict__)
|
||||
self.userdata.set_message(cm.dict())
|
||||
# 等待回传
|
||||
self.userdata.set_token(cm.messageId)
|
||||
self.userdata.set_status_add("status", False)
|
||||
self.userdata.set_status_add("start_timestamp", time.time())
|
||||
topic_resp = f"/jmlink/{device_id}/tml/service/call_resp"
|
||||
self.client.subscribe(topic_resp)
|
||||
self.client.publish(topic, cm())
|
||||
try:
|
||||
while True:
|
||||
if self.userdata.status["status"]:
|
||||
if "code" in self.userdata.status["response"].keys():
|
||||
if self.userdata.status["response"]["code"] != 0:
|
||||
error_code = self.userdata.status['response']['code']
|
||||
logger.Logger.error(f"{topic_resp} 返回错误码: {error_code}")
|
||||
return False, error_code, self.userdata.status['response']['message']
|
||||
else:
|
||||
logger.Logger.info(f"车辆({obj.car_plate_no}) 信息完成{ACTION[obj.action]}")
|
||||
return True, 0, ""
|
||||
if time.time() - self.userdata.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出
|
||||
logger.Logger.error("等待回复超时")
|
||||
return False, -1, "等待回复超时"
|
||||
time.sleep(SLEEP_TIME)
|
||||
finally:
|
||||
self.client.unsubscribe(topic_resp)
|
||||
logger.Logger.debug(f"移除订阅: {topic_resp}")
|
||||
self.userdata.set_token(None)
|
||||
self.userdata.set_status_remove("response")
|
||||
logger.Logger.debug(f"{'=' * 10} 🏁 VehicleRegistration 🏁 {'=' * 10}")
|
||||
|
||||
def update_fixed_card(self, device_id, obj: UpdateFixedCardItem) -> tuple[bool, int, str]:
|
||||
logger.Logger.debug(f"{'=' * 10} 🚩 UpdateFixedCard 🚩 {'=' * 10}")
|
||||
topic = f"/jmlink/{device_id}/tml/service/call"
|
||||
self.userdata.set_topic(topic)
|
||||
logger.Logger.debug(f"{device_id} {ACTION[obj.action]}用户 {obj.plate_number} 的月卡信息")
|
||||
cm = CallMessage("update_fixed_card", obj.__dict__)
|
||||
self.userdata.set_message(cm.dict())
|
||||
# 等待回传
|
||||
self.userdata.set_token(cm.messageId)
|
||||
self.userdata.set_status_add("status", False)
|
||||
self.userdata.set_status_add("start_timestamp", time.time())
|
||||
topic_resp = f"/jmlink/{device_id}/tml/service/call_resp"
|
||||
self.client.subscribe(topic_resp)
|
||||
self.client.publish(topic, cm())
|
||||
try:
|
||||
while True:
|
||||
if self.userdata.status["status"]:
|
||||
if "code" in self.userdata.status["response"].keys():
|
||||
if self.userdata.status["response"]["code"] != 0:
|
||||
error_code = self.userdata.status['response']['code']
|
||||
logger.Logger.error(f"{topic_resp} 返回错误码: {error_code}")
|
||||
return False, error_code, self.userdata.status['response']['message']
|
||||
else:
|
||||
logger.Logger.info(f"车辆({obj.plate_number}) 月卡信息完成修改")
|
||||
return True, 0, ""
|
||||
if time.time() - self.userdata.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出
|
||||
logger.Logger.error("等待回复超时")
|
||||
return False, -1, "等待回复超时"
|
||||
time.sleep(SLEEP_TIME)
|
||||
finally:
|
||||
self.client.unsubscribe(topic_resp)
|
||||
logger.Logger.debug(f"移除订阅: {topic_resp}")
|
||||
self.userdata.set_token(None)
|
||||
self.userdata.set_status_remove("response")
|
||||
logger.Logger.debug(f"{'=' * 10} 🏁 UpdateFixedCard 🏁 {'=' * 10}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sc = ServicesCall()
|
||||
sc.del_face(2, DelFaceItem(
|
||||
user_id="1234",
|
||||
device_ids=str([2])
|
||||
))
|
||||
sc.add_face(2, AddFaceItem(
|
||||
name="测试",
|
||||
user_id="ceshi",
|
||||
face_url="http://ip:port/api/v1/faces/person_demo.jpg",
|
||||
device_ids=str([2, 321]),
|
||||
start_date="2024-01-01T18:00:00.000Z"
|
||||
))
|
||||
|
||||
sc.vehicle_registration(2, VehicleRegistrationItem(
|
||||
car_plate_no="鲁G95339",
|
||||
registration_id="5a12265cf73f261148770c12328bb195",
|
||||
owner_id="1244668310399733760",
|
||||
owner_name="测试业主",
|
||||
registration_time="2024-05-27T16:12:26.895Z",
|
||||
begin_time="2024-05-27T16:12:26.895Z",
|
||||
end_time="2034-05-27T16:12:26.895Z",
|
||||
action="insert",
|
||||
registration_type='0'
|
||||
))
|
||||
|
||||
sc.update_fixed_card(2, UpdateFixedCardItem(
|
||||
vehicle_owner_id="1244668310399733760",
|
||||
vehicle_owner_name="测试业主",
|
||||
vehicle_owner_phone="1244668310399733760",
|
||||
action="insert",
|
||||
card_id=str(int(time.time() * 1000)),
|
||||
effective_date_begin=now_tz_datetime(),
|
||||
effective_date_end=now_tz_datetime(365 * 10),
|
||||
plate_number="鲁G95339"
|
||||
))
|
||||
Reference in New Issue
Block a user