| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891 | # -*- encoding: utf-8 -*-"""@File    : SmartSocketController.py@Time    : 2023/3/17 11:52@Author  : stephen@Email   : zhangdongming@asj6.wecom.work@Software: PyCharm"""import calendarimport datetimeimport loggingimport timeimport requestsfrom dateutil.parser import parsefrom django.db import transactionfrom django.db.models import Sum, Countfrom django.http import QueryDictfrom django.views import Viewfrom Model.models import SocketInfo, SocketSchedule, Device_Info, SocketPowerStatistics, SceneLog, FamilyRoomDevicefrom Object.ResponseObject import ResponseObjectfrom Object.utils import LocalDateTimeUtilfrom Service.CommonService import CommonServiceLOGGER = 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)                status = request_dict.get('status', None)  # 设备当前状态0:关, 1:开, 2:离线                if not all([serial_number, status]):                    return response.json(444, {'error': 'serialNumber and status'})                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()))                # 删除插座电量统计                SocketPowerStatistics.objects.filter(device_id=device_id).delete()                # 删除插座排程                SocketSchedule.objects.filter(device_id=device_id).delete()                # 删除插座开关日志                SceneLog.objects.filter(device_id=serial_number).delete()                # 离线状态下只删除设备电量, 排程和开关日志                if int(status) != 2:                    # 删除插座倒计时                    SocketInfo.objects.filter(device_id=device_id).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)            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)            #  判断上报数据是否为负数            number_list = [watt, power, accumulated_time]            number = CommonService.negative_number_judgment(number_list)            if not number:                if watt < 0:                    watt = 0                if power < 0:                    power = 0                if accumulated_time < 0:                    accumulated_time = 0            now_time = int(time.time())            LOGGER.info('{}上报电量统计data:{}'.format(serial_number, request_dict))            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'] is not 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', '-id')[(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', '-id')[(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, type_switch=0)            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))
 |