Bläddra i källkod

上线智能插座功能模块

zhangdongming 2 år sedan
förälder
incheckning
b0729995f4

+ 2 - 1
Ansjer/server_urls/loocam_url.py

@@ -9,7 +9,7 @@
 from django.urls import re_path
 
 from Controller.SensorGateway import GatewayFamilyRoomController, SubDeviceController, GatewayFamilyMemberController, \
-    EquipmentFamilyController, GatewayDeviceController, SmartSceneController
+    EquipmentFamilyController, GatewayDeviceController, SmartSceneController, SmartSocketController
 
 urlpatterns = [
     re_path(r'^sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
@@ -19,4 +19,5 @@ urlpatterns = [
     re_path(r'^gateway/subdevice/(?P<operation>.*)$', SubDeviceController.GatewaySubDeviceView.as_view()),
     re_path(r'^gateway/device/info/(?P<operation>.*)$', GatewayDeviceController.GatewayDeviceView.as_view()),
     re_path(r'^smartscene/(?P<operation>.*)$', SmartSceneController.SmartSceneView.as_view()),
+    re_path(r'^open/socket/(?P<operation>.*)$', SmartSocketController.SmartSocketView.as_view()),
 ]

+ 1 - 0
Ansjer/urls.py

@@ -352,6 +352,7 @@ urlpatterns = [
     # 网关家庭模块
     url(r'^app/sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
     url(r'^loocam/', include("Ansjer.server_urls.loocam_url")),
+    re_path(r'^api/loocam/', include("Ansjer.server_urls.loocam_url")),
     # 联通4G套餐模块
     url(r'^unicom/', include("Ansjer.server_urls.unicom_url")),
     # 算法小店

+ 7 - 0
Controller/EquipmentManagerV3.py

@@ -746,6 +746,13 @@ class EquipmentManagerV3(View):
                 p['uid_version'] = ''
                 p['ucode'] = ''
             p['View_Password'] = self.encrypt_pwd(p['View_Password'])
+
+            # 判断设备是否支持4G
+            uid_set_qs =UidSetModel.objects.filter(uid=p['UID']).values('mobile_4g')
+            if uid_set_qs.exists():
+                uid_set_qs = uid_set_qs.first()
+                if uid_set_qs['mobile_4g'] == 1:
+                    p['isCameraOpenCloud'] = 0
             data.append(p)
         result = data
         return response.json(0, result)

+ 19 - 6
Controller/SensorGateway/EquipmentFamilyController.py

@@ -17,9 +17,10 @@ from django.views.generic.base import View
 
 from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY
 from Controller.DeviceConfirmRegion import Device_Region
+from Controller.SensorGateway.SmartSocketController import SmartSocketView
 from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidChannelSetModel, \
     iotdeviceInfoModel, UIDModel, Device_User, UserFamily, FamilyMember, FamilyMemberPermission, \
-    FamilyRoomDevice, FamilyRoom, FamilyMemberJoin, GatewaySubDevice, CountryModel
+    FamilyRoomDevice, FamilyRoom, FamilyMemberJoin, GatewaySubDevice, CountryModel, SocketInfo
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -216,7 +217,14 @@ class EquipmentFamilyView(View):
                         'tb_country': country
                     }
                     UidSetModel.objects.create(**uid_set_create_dict)
-                return response.json(0)
+                if int(device_type) == 201:  # 添加插座信息
+                    SmartSocketView.save_socket_switch(device_id, serial_number, 0)
+                res = {
+                    'deviceId': device_id,
+                    'nickName': nick_name,
+                    'serialNumber': serial_number
+                }
+                return response.json(0, res)
         except Exception as e:
             print(e)
             return response.json(177, repr(e))
@@ -764,7 +772,7 @@ class EquipmentFamilyView(View):
             'created_time': now_time
         }
 
-        category = 0 if device_type == 200 else 1
+        category = 0 if device_type == 200 or 201 else 1
         data['category'] = category
         # 查询类别排序
         family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=int(family_id), category=category).values(
@@ -795,7 +803,7 @@ class EquipmentFamilyView(View):
                 for item in device_info_qs:
                     device_id = item['id']
                     device_type = item['Type']
-                    if device_type == 200:
+                    if device_type == 200 or 201:
                         category = 0
                     else:
                         category = 1
@@ -1010,7 +1018,7 @@ class EquipmentFamilyView(View):
         if not permission or permission == '003':
             return response.json(404)
         family_room_device_qs = FamilyRoomDevice.objects \
-            .filter(Q(family_id=family_id), ~Q(device_id__isExist=2), Q(device__userID=user_id)) \
+            .filter(Q(family_id=family_id), ~Q(device_id__isExist=2)) \
             .values().order_by('sort', '-device__data_joined')
         if not family_room_device_qs.exists():
             return response.json(0, device_dict)
@@ -1060,7 +1068,12 @@ class EquipmentFamilyView(View):
                             device_qs['data_joined'] = device_qs['data_joined'].strftime("%Y-%m-%d %H:%M:%S")
                         else:
                             device_qs['data_joined'] = ''
-                    if device_qs['Type'] == 200:
+                    if device_qs['Type'] == 200 or device_qs['Type'] == 201:
+                        if device_qs['Type'] == 201:
+                            socket_info_qs = SocketInfo.objects.filter(device_id=device_qs['id']).values(
+                                'status')
+                            device_qs['socketStatus'] = socket_info_qs.first()[
+                                'status'] if socket_info_qs.exists() else ''
                         gateways.append(device_qs)
                     else:
                         cameras.append(device_qs)

+ 189 - 4
Controller/SensorGateway/GatewayDeviceController.py

@@ -6,16 +6,25 @@
 @Email   : zhangdongming@asj6.wecom.work
 @Software: PyCharm
 """
+import datetime
 import time
 
+import requests
 from django.db import transaction
 from django.db.models import Q
 from django.views.generic.base import View
 
 from Ansjer.Config.gatewaySensorConfig import SMART_SCENE_TOPIC
+from Ansjer.config import CONFIG_INFO, AWS_IOT_SES_ACCESS_CHINA_ID, AWS_IOT_SES_ACCESS_CHINA_SECRET, \
+    AWS_IOT_SES_ACCESS_CHINA_REGION
+from Ansjer.config import LOGGER
 from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
+from Controller.SensorGateway.SmartSocketController import SmartSocketView
 from Model.models import FamilyRoomDevice, FamilyRoom, GatewaySubDevice, Device_Info, UserFamily, FamilyMember, \
-    UidSetModel, iotdeviceInfoModel, SmartScene, SceneLog
+    UidSetModel, iotdeviceInfoModel, SmartScene, SceneLog, SocketInfo, SocketPowerStatistics, SocketSchedule, \
+    CountryModel
+from Object.AWS.AWSIoTDataPlaneUtil import AWSIoTDataPlaneService
+from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -54,6 +63,10 @@ class GatewayDeviceView(View):
             return self.my_family_list(user_id, response)
         elif operation == 'location-setting':
             return self.device_location_setting(user_id, request_dict, response)
+        elif operation == 'bind-serial-user':
+            return self.bind_serial_user(user_id, request_dict, response)
+        elif operation == 'get-serial-user':
+            return self.get_serial_user(user_id, request_dict, response)
 
     @classmethod
     def device_location_setting(cls, user_id, request_dict, response):
@@ -114,6 +127,11 @@ class GatewayDeviceView(View):
             uid_set_qs = UidSetModel.objects.filter(uid=device_info_qs[0].UID)
             if uid_set_qs.exists():
                 uid_set_qs.update(nickname=device_name)
+            if device_info_qs[0].Type == 201:
+                device_info_qs = device_info_qs.values('userID__region_country', 'serial_number')
+                region = device_info_qs[0]['userID__region_country']
+                cls.update_socket(serial_number=device_info_qs[0]['serial_number'], device_name=device_name,
+                                  user_id=user_id, region=region)
         return response.json(0)
 
     @classmethod
@@ -163,6 +181,22 @@ class GatewayDeviceView(View):
                         uid_set_qs = UidSetModel.objects.filter(uid=device_qs.first().UID)
                         if uid_set_qs.exists():
                             uid_set_qs.delete()
+                        socket_info_qs = SocketInfo.objects.filter(device_id=device_id)
+                        if socket_info_qs.exists():
+                            # 设备在不在线, 都发布重置
+                            serial_number = device_qs.first().serial_number
+                            cls.reset_device(serial_number)
+                            socket_info_qs.delete()
+                            socket_power_qs = SocketPowerStatistics.objects.filter(device_id=device_id)
+                            if socket_power_qs.exists():
+                                socket_power_qs.delete()
+                            socket_schedule_qs = SocketSchedule.objects.filter(device_id=device_id)
+                            if socket_schedule_qs.exists():
+                                socket_schedule_qs.delete()
+                            scene_log_qs = SceneLog.objects.filter(device_id=serial_number)
+                            if scene_log_qs.exists():
+                                scene_log_qs.delete()
+                            SmartSocketView.delete_alexa_socket(serial_number)
 
                         # 如果有子设备,删除子设备和关联的场景数据
                         gateway_qs = GatewaySubDevice.objects.filter(device_id=device_id)
@@ -174,9 +208,9 @@ class GatewayDeviceView(View):
                             smart_scene_qs = SmartScene.objects.filter(device_id=device_id)
                         if smart_scene_qs.exists():
                             # 通知设备删除场景id
+                            smart_scene_info = smart_scene_qs.values('id')
                             serial_number = device_qs.first().serial_number
                             topic_name = SMART_SCENE_TOPIC.format(serial_number)
-                            smart_scene_info = smart_scene_qs.values('id')
                             for smart_scene in smart_scene_info:
                                 msg = {
                                     'smart_scene_delete': int(smart_scene['id'])
@@ -188,7 +222,7 @@ class GatewayDeviceView(View):
                                     return response.json(10044)
                                 time.sleep(0.3)
                             smart_scene_qs.delete()
-                        gateway_qs.delete()     # 删除子设备
+                        gateway_qs.delete()  # 删除子设备
                         scene_log_qs = SceneLog.objects.filter(device_id=device_id)
                         if scene_log_qs.exists():
                             scene_log_qs.delete()
@@ -243,6 +277,40 @@ class GatewayDeviceView(View):
             print(e)
             return response.json(177, repr(e))
 
+    @staticmethod
+    def reset_device(serial_number):
+        """
+        下发消息到设备
+        """
+        try:
+            thing_name = 'LC_' + serial_number
+            if 'test' == CONFIG_INFO or CONFIG_INFO == 'cn':
+                # 创建IoT客户端
+                iot_data_plane = AWSIoTDataPlaneService(AWS_IOT_SES_ACCESS_CHINA_ID,
+                                                        AWS_IOT_SES_ACCESS_CHINA_SECRET,
+                                                        AWS_IOT_SES_ACCESS_CHINA_REGION)
+                # 更新影子为离线状态
+                data = {
+                    "state": {
+                        "reported": {
+                            "online": 0
+                        }
+                    }
+                }
+                res = iot_data_plane.update_thing_shadow(thing_name, data)
+                LOGGER.info('删除插座更新设备影子状态{}'.format(res))
+            #  下发设备进行重置
+            SOCKET_TOPIC_NAME = 'loocam/smart-socket/{}'  # 插座发布消息主题(因设备当前版本只能订阅一个主题)
+            topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+            # 发布消息内容,重置设备
+            msg = {'type': 6, 'data': {'device_reset': 1}}
+            result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+            LOGGER.info('重置{}智能插座设备,发布MQTT消息结果{}'.format(serial_number, result))
+            return True
+        except Exception as e:
+            LOGGER.info('插座删除下发更改影子异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
     @classmethod
     def gateway_device_list(cls, request_dict, response):
         """
@@ -287,8 +355,23 @@ class GatewayDeviceView(View):
                 'roomName': gateway_room_name,
                 'iot': iot_data,
                 'roomId': room_id,
-                'familyId': family_id
+                'familyId': family_id,
+                'power': 0,
+                'electricity': 0,
+                'countDownTime': 0,
+                'socketStatus': False,
+                'online': False,
+                'accumulatedTime': 0,
+                'start': False,
             }
+            if device_qs['device__Type'] == 201:
+                socket_info_qs = SocketInfo.objects.filter(device_id=device_id).values('online', 'type_switch',
+                                                                                       'status',
+                                                                                       'count_down_time', 'start')
+                if not socket_info_qs.exists():
+                    return response.json(173)
+                socket_data = cls.smart_socket(device_id, socket_info_qs)
+                gateway = {key: socket_data.get(key, gateway[key]) for key in gateway.keys()}
             family_device_qs = FamilyRoomDevice.objects.filter(device_id=device_id)
             family_device_qs = family_device_qs.filter(~Q(sub_device=0)).order_by('-created_time')
 
@@ -331,6 +414,108 @@ class GatewayDeviceView(View):
             print(e.args)
             return response.json(500)
 
+    @classmethod
+    def smart_socket(cls, device_id, socket_info_qs):
+        """
+        查詢插座信息
+        """
+        nowTime = int(time.time())
+        today = datetime.date.today()
+        #  今天开始时间
+        today_start_time = int(time.mktime(time.strptime(str(today), '%Y-%m-%d')))
+        data = {
+            'power': 0,
+            'electricity': 0,
+            'countDownTime': 0,
+            'accumulatedTime': 0,
+            'socketStatus': False,
+            'online': False,
+            'start': False,
+        }
+        # 插座信息
+        socket_info_qs = socket_info_qs.filter(device_id=device_id).values('online', 'type_switch',
+                                                                           'status', 'count_down_time', 'start')
+        type_switch_list = [type_switch[v] for type_switch in socket_info_qs.values('type_switch') for v in type_switch]
+        #  判断开关类型 0:总开关,1:倒计时开关
+        if len(type_switch_list) == 2:
+            socket_info_qs = socket_info_qs.filter(type_switch=1)
+        else:
+            socket_info_qs = socket_info_qs.filter(type_switch=0)
+        # 插座信息
+        data['socketStatus'] = socket_info_qs[0]['status']
+        data['start'] = socket_info_qs[0]['start']
+        data['online'] = socket_info_qs[0]['online']
+        data['countDownTime'] = socket_info_qs[0]['count_down_time'] if socket_info_qs[0][
+            'count_down_time'] else 0
+        # 当前设备电量信息
+        socket_power_qs = SocketPowerStatistics.objects.filter(device_id=device_id, created_time__gte=today_start_time,
+                                                               created_time__lt=nowTime).values('accumulated_time',
+                                                                                                'power',
+                                                                                                'created_time',
+                                                                                                'electricity'). \
+            order_by('-created_time')
+        if not socket_power_qs.exists():
+            return data
+        data['power'] = round(socket_power_qs[0]['power'], 1)
+        data['electricity'] = round(socket_power_qs[0]['electricity'], 1)
+        data['accumulatedTime'] = socket_power_qs[0]['accumulated_time']
+        return data
+
+    @classmethod
+    def bind_serial_user(cls, user_id, request_dict, response):
+        """
+        绑定网关序列号和用户id
+        @param user_id: 用户id
+        @param request_dict: 请求参数字典
+        @param response: 响应对象
+        @return:
+        """
+        serial_number = request_dict.get('serialNumber')
+        if not serial_number:
+            return response.json(444)
+        try:
+            redis_obj = RedisObject()
+            result = redis_obj.set_data(user_id, serial_number, 300)
+            if not result:
+                return response.json(178)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def get_serial_user(cls, user_id, request_dict, response):
+        """
+        获取用户id绑定网关序列号
+        @param user_id: 用户id
+        @param request_dict: 请求参数字典
+        @param response: 响应对象
+        @return:
+        """
+        try:
+            redis_obj = RedisObject()
+            serial_number = redis_obj.get_data(user_id)
+            if not serial_number:
+                return response.json(173)
+            return response.json(0, {'serialNumber': serial_number})
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def update_socket(cls, serial_number, device_name, user_id, region):
+        url = 'https://www.zositech.xyz/deviceStatus/addOrUpdateSwitch'
+        try:
+            country_qs = CountryModel.objects.filter(id=region).values('region__continent_code')
+            data = {
+                'nick_name': device_name,
+                'serial_number': serial_number,
+                'user_id': user_id,
+                'region': country_qs[0]['region__continent_code'] if country_qs.exists() else 'EN'
+            }
+            requests.post(url=url, data=data, timeout=5)
+        except Exception as e:
+            print(repr(e))
 #
 #                   ___====-_  _-====___
 #             _--^^^#####//      \\#####^^^--_

+ 886 - 0
Controller/SensorGateway/SmartSocketController.py

@@ -0,0 +1,886 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : SmartSocketController.py
+@Time    : 2023/3/17 11:52
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import calendar
+import datetime
+import logging
+import time
+from decimal import Decimal
+
+import requests
+from dateutil.parser import parse
+from django.db import transaction
+from django.db.models import Sum, Count
+from django.http import QueryDict
+from django.views import View
+
+from Model.models import SocketInfo, SocketSchedule, Device_Info, SocketPowerStatistics, SceneLog, FamilyRoomDevice, \
+    CountryModel
+from Object.ResponseObject import ResponseObject
+from Object.utils import LocalDateTimeUtil
+from Service.CommonService import CommonService
+
+LOGGER = logging.getLogger('info')
+SOCKET_TOPIC_NAME = 'loocam/smart-socket/{}'  # 插座发布消息主题(因设备当前版本只能订阅一个主题)
+
+
+class SmartSocketView(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def delete(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        delete = QueryDict(request.body)
+        if not delete:
+            delete = request.GET
+        return self.validation(delete, request, operation)
+
+    def put(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        put = QueryDict(request.body)
+        return self.validation(put, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        ResponseObject('cn')
+        if operation == 'savePowerStatistics':  # 保存电量上报统计
+            return self.save_power_statistics(request_dict, ResponseObject('cn'))
+        elif operation == 'reset':  # 设备复位
+            return self.socket_reset(request_dict, ResponseObject('cn'))
+        elif operation == 'alexa-socket-switch':  # 新增alexa智能开关
+            return self.alexa_socket_switch(request_dict, ResponseObject('cn'))
+        elif operation == 'getSocketState':  # 获取alexa智能开关状态
+            return self.get_socket_state(request_dict, ResponseObject('cn'))
+        token_code, user_id, response = CommonService \
+            .verify_token_get_user_id(request_dict, request)
+        if token_code != 0:
+            return response.json(token_code)
+        if operation == 'saveSwitch':  # 添加插座开关
+            return self.save_switch(request_dict, response)
+        elif operation == 'saveCountDown':  # 添加插座倒计时
+            return self.save_count_down(request_dict, response)
+        elif operation == 'saveSchedule':  # 添加插座排程
+            return self.save_socket_schedule(request_dict, response)
+        elif operation == 'get-all-scene':  # 统计智能插座电量
+            return self.get_all_scene(request_dict, response)
+        elif operation == 'get-socket-schedule':  # 智能插座排程记录查询
+            return self.get_socket_schedule(request_dict, response)
+        elif operation == 'get-log':  # 智能插座开关日志记录查询
+            return self.get_log(request_dict, response)
+        elif operation == 'del-socket-schedule':  # 批量刪除排程
+            return self.del_socket_schedule(request_dict, response, user_id)
+        elif operation == 'get-unit-scene':  # 查詢設備每日/月用電量
+            return self.get_unit_scene(request_dict, response)
+        elif operation == 'get-schedule-data':  # 查询插座记录日期
+            return self.get_schedule_data(request_dict, response)
+        return response.json(404)
+
+    @classmethod
+    def socket_reset(cls, request_dict, response):
+        """
+        智能插座复位删除数据
+        """
+        try:
+            with transaction.atomic():
+                serial_number = request_dict.get('serialNumber', None)
+                if not serial_number:
+                    return response.json(444)
+                socket_info_qs = SocketInfo.objects.filter(serial_number=serial_number, type_switch=0)
+                if not socket_info_qs.exists():
+                    return response.json(173)
+                device_id = socket_info_qs.first().device_id
+                if socket_info_qs.first().status == 1:  # 设备电源开时 恢复为关闭状态
+                    socket_info_qs.update(status=0, updated_time=int(time.time()))
+                # 删除插座倒计时
+                SocketInfo.objects.filter(device_id=device_id).delete()
+                # 删除插座电量统计
+                SocketPowerStatistics.objects.filter(device_id=device_id).delete()
+                # 删除插座排程
+                SocketSchedule.objects.filter(device_id=device_id).delete()
+                # 删除插座开关日志
+                SceneLog.objects.filter(device_id=serial_number).delete()
+                # 删除设备管理家庭接口
+                FamilyRoomDevice.objects.filter(device_id=device_id).delete()
+                # 删除设备
+                Device_Info.objects.filter(id=device_id).delete()
+                # alexa删除插座
+                cls.delete_alexa_socket(serial_number)
+                LOGGER.info('智能插座{}设备已复位'.format(serial_number))
+                return response.json(0)
+        except Exception as e:
+            LOGGER.info('插座复位删除数据异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177)
+
+    @classmethod
+    def save_power_statistics(cls, request_dict, response):
+        """
+        保存设备上报电量统计
+        """
+        try:
+            serial_number = request_dict.get('serialNumber', None)
+            watt = request_dict.get('electricity', 0.00)  # 功率
+            power = request_dict.get('power', 0.00)  # 负载功率
+            # 在线时长秒
+            accumulated_time = request_dict.get('accumulatedTime', None)
+            device_time = request_dict.get('deviceTime', None)
+            LOGGER.info('{}上报电量统计data:{}'.format(serial_number, request_dict))
+            if not all([serial_number, watt, power, accumulated_time, device_time]):
+                return response.json(444)
+            watt = float(watt)
+            power = float(power)
+            accumulated_time = int(accumulated_time)
+            #  判断上报数据是否为负数
+            if watt < 0 or power < 0 or accumulated_time < 0:
+                LOGGER.info('{}插座上报负值data:{}'.format(serial_number, request_dict))
+                return response.json(177)
+            now_time = int(time.time())
+            start_time, end_time = LocalDateTimeUtil.get_today_date(True)
+            # 查询当前序列号当天是否有上传过电量统计
+            power_qs = SocketPowerStatistics.objects.filter(serial_number=serial_number,
+                                                            created_time__gt=start_time,
+                                                            created_time__lte=end_time)
+            data = {
+                'power': power,
+                'updated_time': now_time,
+                'watt': watt
+            }
+            if not power_qs.exists():  # 添加插座上报电量统计
+                socket_info_qs = SocketInfo.objects.filter(serial_number=serial_number).values('device_id')
+                if not socket_info_qs.exists():
+                    return response.json(173)
+                data['device_id'] = socket_info_qs[0]['device_id']
+                data['created_time'] = now_time
+                data['serial_number'] = serial_number
+                data['electricity'] = cls.calculated_power(watt, accumulated_time)
+                data['accumulated_time'] = accumulated_time
+                SocketPowerStatistics.objects.create(**data)
+                return response.json(0)
+            power_vo = power_qs.first()
+            # 累加在线时间目前是以分钟为单位
+            data['accumulated_time'] = power_vo.accumulated_time + accumulated_time
+            # kwh 千瓦时
+            kilowatt_hour = cls.calculated_power(watt, accumulated_time)
+            data['electricity'] = kilowatt_hour + float(power_vo.electricity)
+            # 所消耗累计功率
+            data['watt'] = float(power_vo.watt) + watt
+            # 更新当天电量统计
+            power_qs.update(**data)
+            return response.json(0)
+        except Exception as e:
+            LOGGER.info('智能插座电量存库异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177)
+
+    @staticmethod
+    def calculated_power(watt, minute):
+        """
+        通过每分钟所消耗的功率(瓦)得到千瓦时kwh
+        """
+        if watt == 0 or watt < 0.1 or minute == 0:
+            return 0.00
+        hours = minute / 3600
+        kilowatt_hour = watt * hours / 1000
+        LOGGER.info('瓦计算得到千瓦时结果{}'.format(kilowatt_hour))
+        return kilowatt_hour
+
+    @staticmethod
+    def get_serial_number_by_device_id(deviceId):
+        """
+        根据设备ID获取序列号
+        """
+        device_info = Device_Info.objects.get(id=deviceId)
+        return device_info.serial_number
+
+    @classmethod
+    def save_switch(cls, request_dict, response):
+        """
+        添加开关
+        """
+        device_id = request_dict.get('deviceId', None)
+        status = request_dict.get('status', None)
+        if not all([device_id, status]):
+            return response.json(444)
+        serial_number = cls.get_serial_number_by_device_id(device_id)
+        # 保存数据库并下发MQTT消息到插座设备
+        result = cls.save_socket_switch(device_id, serial_number, int(status))
+        if not result:
+            return response.json(177)
+        return response.json(0)
+
+    @staticmethod
+    def save_socket_switch(device_id, serial_number, status, type_switch=0):
+        """
+        保存插座开关信息
+        @param device_id: 设备ID
+        @param serial_number: 序列号
+        @param status: 状态 0关,1开
+        @param type_switch: 0:总开关,1倒计时开关
+        @return: True | False
+        """
+        if not device_id:
+            return False
+        socket_info_qs = SocketInfo.objects.filter(device_id=device_id, type_switch=type_switch)
+        LOGGER.info('{}进入插座电源开关OR倒计时,类型:{}'.format(serial_number, type_switch))
+        now_time = int(time.time())
+        try:
+            with transaction.atomic():
+                # 创建插座开关信息
+                if not socket_info_qs.exists():
+                    socket_dict = {"device_id": device_id,
+                                   "serial_number": serial_number,
+                                   "status": status,
+                                   "type_switch": type_switch,
+                                   "created_time": now_time,
+                                   "updated_time": now_time,
+                                   "online": True}
+                    SocketInfo.objects.create(**socket_dict)
+                    return True
+                if socket_info_qs.first().status != status:
+                    socket_info_qs.update(status=status, updated_time=now_time)
+                # 主题名称
+                topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+                # 发布消息内容
+                msg = {'type': 1, 'data': {'deviceSwitch': status}}
+                result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+                LOGGER.info('{}智能插座开关设置发布MQTT消息结果{}'.format(serial_number, result))
+                return True
+        except Exception as e:
+            LOGGER.info('智能插座异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @classmethod
+    def save_count_down(cls, request_dict, response):
+        """
+        添加倒计时
+        """
+        device_id = request_dict.get('deviceId', None)
+        status = request_dict.get('status', None)
+        start = request_dict.get('start', None)
+        count_down_time = request_dict.get('countDownTime', None)
+        if not all([device_id, status, count_down_time]):
+            return response.json(444)
+        serial_number = cls.get_serial_number_by_device_id(device_id)
+        # 保存数据库并下发MQTT消息到插座设备
+        result = cls.save_socket_count_down(device_id, serial_number, int(status), int(start), int(count_down_time))
+        if not result:
+            return response.json(177)
+        return response.json(0)
+
+    @staticmethod
+    def save_socket_count_down(device_id, serial_number, status, start, count_down_time, type_switch=1):
+        """
+        保存插座倒计时信息
+        @param count_down_time: 倒计时时间戳
+        @param start: 是否启动倒计时 0:关闭,1:开始
+        @param device_id: 设备ID
+        @param serial_number: 序列号
+        @param status: 倒计时电源状态 0关,1开
+        @param type_switch: 0:总开关,1倒计时开关
+        @return:
+        """
+        if not device_id:
+            return False
+        socket_info_qs = SocketInfo.objects.filter(device_id=device_id, type_switch=type_switch)
+        now_time = int(time.time())
+        try:
+            with transaction.atomic():
+                # 创建插座倒计时信息
+                if not socket_info_qs.exists():
+                    socket_dict = {"device_id": device_id,
+                                   "serial_number": serial_number,
+                                   "status": status,
+                                   "type_switch": type_switch,
+                                   "created_time": now_time,
+                                   "updated_time": now_time,
+                                   "online": True,
+                                   "start": True if start == 1 else False,
+                                   "count_down_time": count_down_time}
+                    socket_info_qs = SocketInfo.objects.create(**socket_dict)
+                    count_down_id = socket_info_qs.id
+                else:
+                    socket_info_qs.update(status=status, count_down_time=count_down_time,
+                                          updated_time=now_time)
+                    count_down_id = socket_info_qs.first().id
+                # 主题名称
+                topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+                # 发布消息内容
+                msg = {'type': 2,
+                       'data': {'powerType': status,
+                                'countDownId': count_down_id,
+                                'time': count_down_time,
+                                'start': start}}
+                result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+                LOGGER.info('智能插座倒计时发布MQTT消息结果{}'.format(result))
+                return True
+        except Exception as e:
+            LOGGER.info('智能插座异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @classmethod
+    def save_socket_schedule(cls, request_dict, response):
+        """
+        插座添加排程
+        """
+        try:
+            device_id = request_dict.get('deviceId', None)
+            task_type = request_dict.get('timeType', None)
+            start_time = request_dict.get('startTime', None)
+            end_time = request_dict.get('endTime', 0)
+            repeat = request_dict.get('repeat', None)
+            task_id = request_dict.get('taskId', None)
+            device_switch = request_dict.get('deviceSwitch', None)
+            task_switch = request_dict.get('taskSwitch', None)
+            if not all([task_type, start_time, end_time, repeat, device_switch, task_switch]):
+                return response.json(444)
+            device_switch = int(device_switch)
+            task_switch = int(task_switch)
+            now_time = int(time.time())
+            task_type = int(task_type)
+            end_time = int(end_time) if task_type == 2 else 0
+            data = {'time_type': task_type, 'start_time': int(start_time), 'repeat': int(repeat),
+                    'switch_status': True if device_switch == 1 else False,
+                    'task_status': True if task_switch == 1 else False}
+            serial_number = cls.get_serial_number_by_device_id(device_id)
+            if task_id:  # 修改排程
+                task_id = int(task_id)
+                socket_schedule_qs = SocketSchedule.objects.filter(id=task_id)
+                if not socket_schedule_qs.exists():
+                    return response.json(174)
+                if end_time:
+                    data['end_time'] = end_time
+                data['updated_time'] = now_time
+                socket_schedule_qs.update(**data)
+            else:
+                # 查询是否已设置过当前排程
+                socket_s_qs = SocketSchedule.objects.filter(device_id=device_id,
+                                                            start_time=int(start_time),
+                                                            end_time=end_time,
+                                                            time_type=task_type)
+                if socket_s_qs.exists():
+                    return response.json(174)
+                schedule_count = SocketSchedule.objects.filter(device_id=device_id).count()
+                if schedule_count >= 20:
+                    return response.json(10061)
+                # 添加排程
+                data['device_id'] = device_id
+                data['end_time'] = end_time
+                data['serial_number'] = serial_number
+                data['updated_time'] = now_time
+                data['created_time'] = now_time
+                socket_schedule = SocketSchedule.objects.create(**data)
+                task_id = socket_schedule.id
+                # 将排程任务下发给设备
+                cls.send_socket_schedule(serial_number, task_id, task_type, int(start_time),
+                                         end_time, int(repeat), device_switch,
+                                         task_switch)
+            return response.json(0)
+        except Exception as e:
+            LOGGER.info('智能插座异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @staticmethod
+    def send_socket_schedule(serial_number, task_id, time_type, start_time, end_time, repeat, device_switch,
+                             task_switch):
+        """
+        排程下发设备
+        @param serial_number: 序列号
+        @param task_id: 当前排程任务id
+        @param time_type: 任务类型 0:设定时间,1:设定时间段
+        @param start_time: 开启时间
+        @param end_time: 结束时间
+        @param repeat: 重复日期
+        @param device_switch: 任务执行后期望设备状态,0:关闭,1:开启
+        @param task_switch: 任务执行状态 0:不执行,1:执行
+        @return: True | False
+        """
+        msg = {
+            'type': 3,
+            'data': {'taskId': task_id, 'timeType': time_type,
+                     'startTime': start_time, 'endTime': end_time,
+                     'repeat': repeat,
+                     'deviceSwitch': device_switch,
+                     'taskSwitch': task_switch}
+        }
+        # 主题名称
+        topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+        result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+        LOGGER.info('智能插座{}排程任务发布MQTT消息结果{}'.format(serial_number, result))
+        return result
+
+    # 以下是查询智能插座接口
+    @staticmethod
+    def get_all_scene(request_dict, response):
+        """
+        统计智能插座电量
+        @request_dict serialNumber: 序列号
+        @request_dict unit: 时间单位
+        @param request_dict: 请求数据
+        @param response: 响应
+        @return: response
+        """
+        serial_number = request_dict.get('serialNumber', None)
+        # 确定是否会传值
+        if not all([serial_number]):
+            return response.json(444, {'error param': 'serialNumber'})
+        all_socket_power_qs = SocketPowerStatistics.objects.filter(serial_number=serial_number).values('electricity',
+                                                                                                       'accumulated_time',
+                                                                                                       'power',
+                                                                                                       'created_time'). \
+            order_by('-created_time')
+        if not all_socket_power_qs.exists():
+            return response.json(0, {})
+        try:
+            data = {}
+            # 设备累计电量
+            all_electricity = all_socket_power_qs.aggregate(total=Sum('electricity'))
+            data['electricityAll'] = round(all_electricity['total'], 1)
+
+            # 本月电费
+            nowTime = int(time.time())
+            nowTime = CommonService.timestamp_to_str(nowTime)
+            year, month = str(nowTime).split('-')[0], str(nowTime).split('-')[1]
+            end = calendar.monthrange(int(year), int(month))[1]
+            startTime_now = parse('%s-%s-01 00:00:00' % (year, month))
+            endTime_now = parse('%s-%s-%s 23:59:59' % (year, month, end))
+            startTime_now = CommonService.str_to_timestamp(str(startTime_now))
+            endTime_now = CommonService.str_to_timestamp(str(endTime_now))
+            electricity = all_socket_power_qs.filter(created_time__gte=startTime_now,
+                                                     created_time__lt=endTime_now).aggregate(
+                total=Sum('electricity'))
+            if electricity['total'] != None:
+                data['electricityMonth'] = round(electricity['total'], 1)
+            else:
+                data['electricityMonth'] = 0
+
+            # 获取当前日期
+            nowTime = int(time.time())
+            today = datetime.date.today()
+            #  今天开始时间
+            today_start_time = int(time.mktime(time.strptime(str(today), '%Y-%m-%d')))
+            today_socket_power_qs = all_socket_power_qs.filter(created_time__gte=today_start_time,
+                                                               created_time__lt=nowTime).values('electricity',
+                                                                                                'accumulated_time',
+                                                                                                'power',
+                                                                                                'created_time')
+            # 当天使用电量
+            data['electricityToday'] = round(today_socket_power_qs[0]['electricity'],
+                                             1) if today_socket_power_qs.exists() else 0
+            # 当天累计时长
+            data['accumulated_time'] = today_socket_power_qs[0][
+                'accumulated_time'] if today_socket_power_qs.exists() else 0
+            # 当前功率
+            data['power'] = round(today_socket_power_qs[0]['power'], 1) if today_socket_power_qs.exists() else 0
+
+            # 昨天使用电量
+            yesterday = today - datetime.timedelta(days=1)
+            # 昨天开始时间戳
+            yesterday_start_time = int(time.mktime(time.strptime(str(yesterday), '%Y-%m-%d')))
+            # 昨天结束时间戳
+            yesterday_end_time = int(time.mktime(time.strptime(str(today), '%Y-%m-%d'))) - 1
+            socket_qs = all_socket_power_qs.filter(created_time__gte=yesterday_start_time,
+                                                   created_time__lt=yesterday_end_time).values('electricity')
+            if socket_qs.exists():
+                data['electricityYesterday'] = round(socket_qs[0]['electricity'], 1)
+            else:
+                data['electricityYesterday'] = 0
+            return response.json(0, data)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_socket_schedule(request_dict, response):
+        """
+        智能插座排程记录查询
+        @param request_dict: 请求参数
+        @request_dict page: 页数
+        @request_dict size: 条数
+        @request_dict serialNumber: 设备序列号
+        @param response: 响应对象
+        @return: response
+        """
+        page = request_dict.get('pageNo', None)
+        size = request_dict.get('pageSize', None)
+        serial_number = request_dict.get('serialNumber', None)
+
+        if not all([page, size, serial_number]):
+            return response.json(444)
+        page, size = int(page), int(size)
+        socket_schedule_qs = SocketSchedule.objects.filter(serial_number=serial_number).values('switch_status',
+                                                                                               'start_time',
+                                                                                               'end_time',
+                                                                                               'repeat',
+                                                                                               'task_status',
+                                                                                               'time_type',
+                                                                                               'created_time',
+                                                                                               'updated_time',
+                                                                                               'device_id',
+                                                                                               'id').order_by(
+            '-created_time')[(page - 1) * size:page * size]
+        if not socket_schedule_qs.exists():
+            return response.json(0, [])
+        try:
+            schedule_list = []
+            for socket_schedule in socket_schedule_qs:
+                schedule_list.append({
+                    'taskId': socket_schedule['id'],
+                    'deviceID': socket_schedule['device_id'],
+                    'serialNumber': serial_number,
+                    'timeType': socket_schedule['time_type'],
+                    'startTime': socket_schedule['start_time'],
+                    'endTime': socket_schedule['end_time'],
+                    'switchStatus': socket_schedule['switch_status'],
+                    'taskStatus': socket_schedule['task_status'],
+                    # 进制
+                    'repeat': socket_schedule['repeat'],
+                })
+            return response.json(0, schedule_list)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_log(request_dict, response):
+        """
+        智能插座开关日志记录查询
+        @param request_dict: 请求参数
+        @request_dict page: 页数
+        @request_dict size: 条数
+        @request_dict serialNumber: 设备序列号
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param response: 响应对象
+        @return: response
+        # 日誌擦護用序列號查詢
+        """
+        page = request_dict.get('page', None)
+        size = request_dict.get('size', None)
+        serial_number = request_dict.get('serialNumber', None)
+        startTime = request_dict.get('startTime', None)
+        endTime = request_dict.get('endTime', None)
+        if not all([page, size, serial_number]):
+            return response.json(444, {'errno: page or size or serial_number'})
+        page, size = int(page), int(size)
+
+        try:
+            if startTime is None and endTime is None:
+                scene_log_qs = SceneLog.objects.filter(device_id=serial_number).values('tasks', 'status',
+                                                                                       'created_time').order_by(
+                    '-created_time')[(page - 1) * size:page * size]
+                if not scene_log_qs.exists():
+                    return response.json(0, [])
+            else:
+                scene_log_qs = SceneLog.objects.filter(device_id=serial_number, created_time__gte=startTime,
+                                                       created_time__lt=endTime).values('tasks', 'status',
+                                                                                        'created_time').order_by(
+                    '-created_time')[(page - 1) * size:page * size]
+                if not scene_log_qs.exists():
+                    return response.json(0, [])
+            log_list = []
+            for scene_log in scene_log_qs:
+                data = {
+                    'serialNumber': serial_number,
+                    'tasks': scene_log['tasks'] if scene_log['tasks'] else '',
+                    'status': scene_log['status'],
+                    'createdTime': scene_log['created_time'],
+                }
+                log_list.append(data)
+            return response.json(0, log_list)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @classmethod
+    def splittings_time(cls, startTime, endTime, unit):
+        """
+        根據時間單位分割時間
+        """
+        diction = {}
+        time_list = []
+        # 开始时间
+        startTime = CommonService.timestamp_to_str(int(startTime))
+        endTime = CommonService.timestamp_to_str(int(endTime))
+        startYear, startMonth, startDay = \
+            str(startTime).split('-')[0], str(startTime).split('-')[1], str(startTime).split('-')[2]
+        # 结束时间
+        endYear, endMonth, endDay = str(endTime).split('-')[0], str(endTime).split('-')[1], str(endTime).split('-')[
+            2]
+        if unit == 'week' or unit == 'month':
+            startTime = parse('%s-%s-%s' % (startYear, startMonth, startDay))
+            endTime = parse('%s-%s-%s' % (endYear, endMonth, endDay))
+            time_list = CommonService.cutting_time(startTime, endTime, time_unit='day')
+        elif unit == 'year':
+            startYear, startMonth = int(startTime.split('-')[0]), int(startTime.split('-')[1])
+            endYear, endMonth = int(endTime.split('-')[0]), int(endTime.split('-')[1])
+            # 获取下个月的第一天
+            if startMonth == 12:
+                startYear += 1
+                startMonth = 1
+            else:
+                startMonth += 1
+            #  计算(开始月,结束月)
+            startTime = parse('%s-%s-01 00:00:00' % (str(startYear), str(startMonth)))
+            # 获取上个月最后一天
+            if endMonth == 1:
+                endYear -= 1
+                endMonth = 12
+            else:
+                endMonth -= 1
+            endDay = calendar.monthrange(endYear, endMonth)[1]
+            endTime = parse('%s-%s-%s 23:59:59' % (str(endYear), str(endMonth), endDay))
+            time_list = CommonService.cutting_time(startTime, endTime, time_unit='month')
+            #  开始月的时间区间
+            startMonth_time = CommonService.str_to_timestamp(str(startTime))
+            #  结束月的时间区间
+            endMonth_time = CommonService.str_to_timestamp(str(endTime))
+            diction['startMonth_time'] = startMonth_time
+            diction['endMonth_time'] = endMonth_time
+        diction['time_list'] = time_list
+        return diction
+
+    @staticmethod
+    def del_socket_schedule(request_dict, response, user_id):
+        """
+        批量刪除排程
+        @param request_dict: 请求参数
+        @param user_id: 用戶user_id
+        @request_dict ids: 排程id
+        @request_dict serialNumber: 设备序列号
+        @param response: 响应对象
+        @return: response
+        """
+        try:
+            with transaction.atomic():
+                ids = request_dict.get('ids', None)
+                serial_number = request_dict.get('serialNumber', None)
+                if not all({ids, serial_number}):
+                    return response.json(444, {'error param': 'id or serialNumber'})
+                device_info_qs = Device_Info.objects.filter(userID_id=user_id, serial_number=serial_number)
+                if not device_info_qs.exists():
+                    return response.json(173)
+                socket_schedule_qs = SocketSchedule.objects.filter(id__in=ids.split(','))
+                if not socket_schedule_qs.exists():
+                    return response.json(173)
+                # 发布MQTT消息通知设备删除排程任务
+                # for val in socket_schedule_qs:
+                #     if val.task_status:
+                #         switch_status = 1 if val.switch_status else 0
+                #         result = SmartSocketView.send_socket_schedule(val.serial_number, val.id, val.time_type,
+                #                                                       val.start_time, val.end_time,
+                #                                                       val.repeat, switch_status, 0)
+                #         LOGGER.info('删除排程发布结果:{}'.format(result))
+                socket_schedule_qs.delete()
+                return response.json(0)
+        except Exception as e:
+            LOGGER.info('插座排程删除数据异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177)
+
+    @classmethod
+    def get_unit_scene(cls, request_dict, response):
+        """
+        查詢設備每日/月用電量
+        @request_dict serialNumber: 设备序列号
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serialNumber', None)
+        unit = request_dict.get('unit', None)
+        startTime = request_dict.get('startTime', None)
+        endTime = request_dict.get('endTime', None)
+        if not all([unit, startTime, endTime, serial_number]):
+            return response.json(500, {'errno': 'unit or startTime or endTime or serialNumber'})
+        try:
+            socket_power_qs = SocketPowerStatistics.objects.filter(serial_number=serial_number). \
+                values('electricity', 'accumulated_time', 'power', 'created_time')
+            if not socket_power_qs.exists():
+                return response.json(0, {})
+            #  时间和功耗
+            data = {}
+            new_list = []
+            socket_qs = socket_power_qs.filter(created_time__gte=startTime, created_time__lt=endTime).aggregate(
+                electricity=Sum('electricity'), accumulatedTime=Sum('accumulated_time'))
+            data['electricityTimeAll'] = round(socket_qs['electricity'], 2) if socket_qs[
+                'electricity'] else 0
+            data['accumulatedTimeAll'] = socket_qs['accumulatedTime'] if socket_qs['accumulatedTime'] else 0
+
+            #  分割时间
+            diction = cls.splittings_time(startTime, endTime, unit)
+            if unit == 'year':
+                # 开始月
+                socket_qs = socket_power_qs.filter(created_time__gte=startTime,
+                                                   created_time__lt=diction['startMonth_time']).aggregate(
+                    electricity=Sum('electricity'), accumulatedTime=Sum('accumulated_time'))
+                electricity = socket_qs['electricity'] if socket_qs[
+                    'electricity'] else 0
+                # 標記月日
+                subscript = cls.get_subscript(unit, startTime)
+                new_list.append({
+                    'subscript': subscript,
+                    'time': int(startTime),
+                    'electricity': round(electricity, 2)
+                })
+            # 查询天月
+            for item in diction['time_list']:
+                socket_qs = socket_power_qs.filter(created_time__gte=item[0],
+                                                   created_time__lt=item[1]).aggregate(
+                    electricity=Sum('electricity'))
+                electricity = socket_qs['electricity'] if socket_qs[
+                    'electricity'] else 0
+                # 標記月日
+                subscript = cls.get_subscript(unit, item[0])
+                new_list.append({
+                    'subscript': subscript,
+                    'time': item[0],
+                    'electricity': round(electricity, 2)
+                })
+
+            if unit == 'year':
+                # 结束月
+                socket_qs = socket_power_qs.filter(created_time__gte=diction['endMonth_time'],
+                                                   created_time__lt=endTime).aggregate(
+                    electricity=Sum('electricity'))
+                electricity = socket_qs['electricity'] if socket_qs[
+                    'electricity'] else 0
+                # 標記月日
+                subscript = cls.get_subscript(unit, endTime)
+                new_list.append({
+                    'subscript': subscript,
+                    'time': int(endTime),
+                    'electricity': round(electricity, 2)
+                })
+            #  降序排序
+            # new_list.sort(key=lambda k: k["time"], reverse=True)
+            data['week_or_month_or_year'] = new_list
+            return response.json(0, data)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @classmethod
+    def get_subscript(cls, unit, time_stamp):
+        """
+        標記月日
+        @param unit: 时间单位
+        @param time_stamp: 时间戳
+        @return: subscript
+        """
+        time_tuple = time.localtime(int(time_stamp))  # 把时间戳转换成时间元祖
+        time_tuple = time.strftime('%Y-%m-%d-%w', time_tuple)  # 把时间元祖转换成格式化好的时间
+        if unit == 'week' or unit == 'year':
+            if unit == 'week':
+                subscript = int(str(time_tuple).split('-')[3])
+                return subscript
+            else:
+                Year, Month, Day = int(time_tuple.split('-')[0]), int(time_tuple.split('-')[1]), int(
+                    time_tuple.split('-')[2])
+                subscript = datetime.date(Year, Month, Day).month
+                subscript -= 1
+                return subscript
+        else:
+            Year, Month, Day = int(time_tuple.split('-')[0]), int(time_tuple.split('-')[1]), int(
+                time_tuple.split('-')[2])
+            subscript = datetime.date(Year, Month, Day).day
+            subscript -= 1
+            return subscript
+
+    @staticmethod
+    def get_schedule_data(request_dict, response):
+        """
+        查询插座日志记录日期
+        @request_dict serialNumber: 设备序列号
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serialNumber', None)
+        if not serial_number:
+            return response.json(444, {'error': 'serialNumber'})
+
+        try:
+            socket_schedule_qs = SceneLog.objects.extra(
+                select={'date': "FROM_UNIXTIME(created_time,'%%Y-%%m-%%d')"}).values('date').filter(
+                device_id=serial_number).annotate(count=Count('created_time')).order_by('-date')[:31]
+            schedule_date_list = []
+            for socket_schedule in socket_schedule_qs:
+                schedule_date_list.append({
+                    'timestamp': CommonService.str_to_timestamp(socket_schedule['date'], '%Y-%m-%d'),
+                    'count': socket_schedule['count'],
+                    'format': socket_schedule['date']
+                })
+            return response.json(0, schedule_date_list)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @classmethod
+    def alexa_socket_switch(cls, request_dict, response):
+        """
+        alexa智能开关
+        @request_dict serialNumber: 设备序列号
+        @request_dict status: 开关状态
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: response
+        """
+        serialNumber = request_dict.get('serial_number', None)
+        status = request_dict.get('power_controller', None)
+        if not all([serialNumber, status]):
+            return response.json(444)
+        # 同步数据库并下发MQTT消息到插座设备
+        try:
+            socket_info_qs = SocketInfo.objects.get(serial_number=serialNumber)
+            device_id = socket_info_qs.device_id
+            result = cls.save_socket_switch(device_id, serialNumber, int(status))
+            if not result:
+                return response.json(177)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @classmethod
+    def get_socket_state(cls, request_dict, response):
+        """
+        获取alexa智能开关状态
+        @request_dict serialNumber: 设备序列号
+        @request_dict status: 开关状态
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serial_number', None)
+        if not all([serial_number]):
+            return response.json(444)
+        # 同步数据库并下发MQTT消息到插座设备
+        try:
+            socket_info_qs = SocketInfo.objects.filter(serial_number=serial_number).values('status')
+            if socket_info_qs.exists():
+                res = {
+                    'power_state': socket_info_qs[0]['status']
+                }
+                return response.json(0, res)
+            return response.json(173)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @classmethod
+    def delete_alexa_socket(cls, serial_number):
+        url = 'https://www.zositech.xyz/deviceStatus/deleteSwitch'
+        data = {
+            'serial_number': serial_number
+        }
+        try:
+            requests.post(url=url, data=data, timeout=5)
+        except Exception as e:
+            print(repr(e))

+ 47 - 0
Object/AWS/AWSIoTDataPlaneUtil.py

@@ -0,0 +1,47 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : AWSIoTDataPlaneUtil.py
+@Time    : 2023/4/13 16:43
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+@Document: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iot-data.html#iotdataplane
+"""
+import json
+import logging
+
+import boto3
+
+LOGGER = logging.getLogger('info')
+
+
+class AWSIoTDataPlaneService:
+    def __init__(self, aws_access_key_id, secret_access_key, region_name):
+        self.client = boto3.client(
+            'iot-data',
+            aws_access_key_id=aws_access_key_id,
+            aws_secret_access_key=secret_access_key,
+            region_name=region_name
+        )
+
+    def update_thing_shadow(self, thing_name, data, shadow_name=None):
+        """
+        更新指定事物的影子
+        @param thing_name: 物品名称
+        @param data: 更新数据
+        @param shadow_name: 自定义影子名称(使用经典影子可不填)
+        @return: 更新状态
+        """
+        try:
+            params = {
+                'thingName': thing_name,
+                'payload': json.dumps(data)
+            }
+            if shadow_name:
+                params['shadowName'] = shadow_name
+            response = self.client.update_thing_shadow(**params)
+            assert response['ResponseMetadata']['HTTPStatusCode'] == 200
+            return True
+        except Exception as e:
+            LOGGER.info('更新设备影子异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False

+ 2 - 0
Service/UserDeviceService.py

@@ -37,6 +37,8 @@ class UserDeviceService:
             dv_qs = dv_qs.filter(NickName=nickname)
         if uid:
             dv_qs = dv_qs.filter(UID=uid)
+        # 周视首页过滤网关以及插座类型
+        dv_qs = dv_qs.exclude(Type__in=[200, 201])
         dv_qs = dv_qs.values('id', 'userID', 'NickName', 'UID', 'View_Account', 'View_Password', 'ChannelIndex',
                              'Type', 'isShare', 'primaryUserID', 'primaryMaster', 'data_joined', 'vodPrimaryUserID',
                              'vodPrimaryMaster', 'userID__userEmail', 'version', 'isVod', 'isExist', 'NotificationMode',