Explorar el Código

Merge branch 'test'

lang hace 3 años
padre
commit
4ea93c6e0c

+ 21 - 1
Ansjer/config.py

@@ -447,4 +447,24 @@ APNS_CODE = {
 APP_TYPE = {
     1: 'ios',
     2: 'android'
-}
+}
+
+# 联通Unicom config
+# 应用地址,请向开发人员索取
+unicomAppUrl = 'https://chinaunicom-iot.unimip.cn'
+# 应用id,请向开发人员创建应用,分配appId
+unicomAppId = 'LNO7ojB7mZU5ep9IuiHvygVWbwaO9vt0'
+# 应用密匙,请向开发人员创建应用,分配appSecret
+unicomAppSecret = 'p8MT1CS4QAVl0xb4cp7VOCgMvtQp2O43'
+# 租户/产品ID,请向开发人员索取
+unicomTenantId = '1469181295663300608'
+# 密码加密密匙,请向开发人员索取
+unicomEncodeKey = 'uBdUx82vPHkDKb284d7NkjFoNcKWBuka'
+# 密码加密参数,请向开发人员索取
+unicomIvKey = 'oCRU0D1wKfBlNeTz'
+# 用户名,如无请联系客户经理开通
+unicomUserName = 'zh-zhasjdz'
+# 登录密码,如无请联系客户经理
+unicomPassword = 'XoROL1vCl5@_'
+# 回调签名验证加密密匙,请向开发人员索取
+unicomPushKey = 'NVVDQMBSOJTXA'

+ 9 - 8
Controller/CouponController.py

@@ -50,25 +50,26 @@ class CouponView(View):
         username = request_dict.get('username', None)
         num = request_dict.get('num', None)
         userID = Device_User.objects.filter(username=username).values('userID')[0]['userID']
+        coupon_config_id = request_dict.get('coupon_config_id', 1)
 
         try:
             data = []
             # CouponConfigModel.objects.create(type=1, use_range=1, coupon_discount=8)
-            # CouponLang.objects.create(
-            #     lang='en',
-            #     instruction='for the first month of the Auto-renewal plan',
-            #     quota='20.0%',
-            #     unit='off',
-            #     remark='This coupon can be used on each device once only.'
+            # CouponLangObj = CouponLang.objects.create(
+            #     lang='cn',
+            #     instruction='用于自动续费套餐的首月',
+            #     quota='',
+            #     unit='',
+            #     remark='每台摄像机上只能用一次'
             # )
-            # CouponConfigModel.objects.get(id=1).lang.add(1)
+            # CouponConfigModel.objects.get(id=1).lang.add(CouponLangObj.id)
             now_time = int(time.time())
             CouponModel.objects.create(
                 use_status=0,
                 distribute_time=now_time,
                 valid_time=now_time+10000000,
                 userID=userID,
-                coupon_config_id=1,
+                coupon_config_id=coupon_config_id,
                 update_time=now_time,
                 create_time=now_time
             )

+ 4 - 0
Controller/PaymentCycle.py

@@ -197,6 +197,10 @@ class PaypalCycleNotify(View):
                          ))
             logger.info('billing_agreement_state')
             logger.info(state)
+            red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            if lang != 'cn':
+                red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            return HttpResponseRedirect(red_url)
         try:
             userid = order_list[0]['userID__userID']
             username = order_list[0]['userID__username']

+ 23 - 0
Controller/SensorGateway/EquipmentFamilyController.py

@@ -64,6 +64,9 @@ class EquipmentFamilyView(View):
         # 获取家庭列表
         elif operation == 'family-list':
             return self.get_family_list(user_id, request_dict, response)
+        # 查询所在家庭列表
+        elif operation == "where-family-list":
+            return self.who_family_list(user_id, response)
         # 家庭保存
         elif operation == 'family-save':
             return self.family_save(user_id, request_dict, response)
@@ -590,6 +593,26 @@ class EquipmentFamilyView(View):
                 return response.json(0, items)
         return response.json(309)
 
+    @staticmethod
+    def who_family_list(user_id, response):
+        """
+        查询我加入的家庭集合与我创建的家庭集合
+        @param user_id:
+        @param response:
+        @return:
+        """
+        join_family_qs = FamilyMember.objects.filter(user_id=user_id, identity=0) \
+            .order_by('sort').values('identity', 'family_id', 'family__name', 'permission_id', 'permission__no',
+                                     'family__location', 'user__username', 'user__userIconUrl')
+        join_family_list = EquipmentFamilyView.family_info_list(join_family_qs)
+
+        my_family_qs = FamilyMember.objects.filter(user_id=user_id, identity=1) \
+            .order_by('sort').values('identity', 'family_id', 'family__name', 'permission_id', 'permission__no',
+                                     'family__location', 'user__username', 'user__userIconUrl')
+        my_family_list = EquipmentFamilyView.family_info_list(my_family_qs)
+
+        return response.json(0, {'myFamilyList': my_family_list, 'joinFamilyList': join_family_list})
+
     @staticmethod
     def family_info_list(family_member_qs):
         items = []

+ 2 - 1
Controller/SensorGateway/GatewayDeviceController.py

@@ -255,7 +255,8 @@ class GatewayDeviceView(View):
                         'ieeeAddr': gateway_sub_qs['ieee_addr'],
                         'familyId': family_id,
                     })
-            return response.json(0, {'gateway': gateway, 'sub_device': sub_device})
+            res = {'gateway': gateway, 'sub_device': sub_device, 'sub_device_count': len(sub_device), 'scene_count': 0}
+            return response.json(0, res)
 
         except Exception as e:
             print(e.args)

+ 62 - 4
Controller/SensorGateway/GatewayFamilyRoomController.py

@@ -8,7 +8,7 @@
 """
 
 from django.db import transaction
-from django.db.models import Q, Count
+from django.db.models import Q, Count, F
 from django.views.generic.base import View
 
 from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
@@ -50,6 +50,12 @@ class GatewayFamilyRoomView(View):
         # 房间详情
         elif operation == 'details':
             return self.get_room_details(app_user_id, request_dict, response)
+        elif operation == 'all-devices':    # 家庭所有设备
+            return self.all_devices(request_dict, response)
+        elif operation == 'devices-sort':    # 家庭设备排序
+            return self.devices_sort(request_dict, response)
+        else:
+            return response.json(414)
 
     @classmethod
     def room_device_save(cls, app_user_id, request_dict, response):
@@ -136,9 +142,8 @@ class GatewayFamilyRoomView(View):
             return response.json(444)
         items = ids.split(',')
         for item in items:
-            vals = item.split('-')
-            room_id = vals[0]
-            sort = vals[1]
+            item = item.split('-')
+            room_id, sort = item[0], item[1]
             family_room = FamilyRoom.objects.filter(id=int(room_id))
             if family_room.exists():
                 family_room.update(sort=int(sort))
@@ -193,3 +198,56 @@ class GatewayFamilyRoomView(View):
                     'roomName': name
                 })
         return response.json(0, {'deviceRooms': device_room, 'deviceNotRooms': device_not_room})
+
+    @staticmethod
+    def all_devices(request_dict, response):
+        """
+        家庭所有设备(网关和摄像头设备)
+        @param request_dict: 请求参数
+        @request_dict familyId: 家庭id
+        @param response: 响应参数
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        try:
+            family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id, sub_device=0).\
+                annotate(type=F('device__Type'), nickname=F('device__NickName')).\
+                values('device_id', 'type', 'nickname', 'room_id').order_by('sort')
+            if not family_room_device_qs.exists():
+                return response.json(0, [])
+            # 查询房间名称
+            for device in family_room_device_qs:
+                room_id = device['room_id']
+                if room_id == 0:
+                    device['room'] = ''
+                else:
+                    family_room_qs = FamilyRoom.objects.filter(id=room_id).values('name')
+                    device['room'] = family_room_qs[0]['name'] if family_room_qs.exists() else ''
+                device.pop('room_id')
+            return response.json(0, list(family_room_device_qs))
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def devices_sort(request_dict, response):
+        """
+        家庭设备排序
+        @param request_dict: 请求参数
+        @request_dict 设备id: deviceIds
+        @param response: 响应参数
+        @return:
+        """
+        device_ids = request_dict.get('deviceIds', None)
+        if not device_ids:
+            return response.json(444)
+        try:
+            device_ids = device_ids.split(',')
+            with transaction.atomic():
+                for i, item in enumerate(device_ids):
+                    device_id = int(item)
+                    FamilyRoomDevice.objects.filter(device_id=device_id).update(sort=i)
+            return response.json(0)
+        except Exception as e:
+            return response.json(500, repr(e))

+ 44 - 29
Controller/SensorGateway/SubDeviceController.py

@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 """
-@Author : Joker
+@Author : Rocky
 @Time : 2022/5/25 15:17
 @File :SubDeviceController.py
 """
@@ -37,9 +37,9 @@ class GatewaySubDeviceView(View):
             return response.json(token_obj.code)
         user_id = token_obj.userID
         if operation == 'add':  # 添加子设备
-            return self.add(request_dict, user_id, response)
-        elif operation == 'query':  # 查询子设备
-            return self.query(request_dict, user_id, response)
+            return self.add_sub_device(request_dict, user_id, response)
+        elif operation == 'detail':  # 查询子设备信息
+            return self.query_sub_device(request_dict, response)
         elif operation == 'update':  # 更新子设备信息
             return self.sensor_update(request_dict, response)
         elif operation == 'delete':  # 删除子设备
@@ -54,16 +54,23 @@ class GatewaySubDeviceView(View):
             return response.json(414)
 
     @staticmethod
-    def add(request_dict, user_id, response):
+    def add_sub_device(request_dict, user_id, response):
         """
         添加子设备
         @param request_dict: 请求参数
-        @request_dict serial_number: 序列号
-        @request_dict device_type: 设备类型
-        @request_dict nickname: 设备名
-        @request_dict src_addr: 短地址
-        @request_dict family_id: 家庭id
-        @request_dict room_id: 房间id
+        @request_dict serialNumber: 序列号
+        @request_dict deviceType: 设备类型
+        @request_dict nickName: 设备名
+        @request_dict ieeeAddr: 长地址
+        @request_dict srcAddr: 短地址
+        @request_dict mac: mac地址
+        @request_dict deviceModel: 设备型号
+        @request_dict manufacturer: 制造商
+        @request_dict sensorSerial: 传感器序列号
+        @request_dict firmwareVersion: 固件版本
+        @request_dict hardwareVersion: 硬件版本
+        @request_dict familyId: 家庭id
+        @request_dict roomId: 房间id
         @param user_id: 用户id
         @param response: 响应对象
         @return: response 响应对象
@@ -73,6 +80,13 @@ class GatewaySubDeviceView(View):
         nickname = request_dict.get('nickName', None)
         ieee_addr = request_dict.get('ieeeAddr', None)
         src_addr = request_dict.get('srcAddr', None)
+        mac = request_dict.get('mac', '')
+        device_model = request_dict.get('deviceModel', '')
+        manufacturer = request_dict.get('manufacturer', '')
+        sensor_serial = request_dict.get('sensorSerial', '')
+        firmware_version = request_dict.get('firmwareVersion', '')
+        hardware_version = request_dict.get('hardwareVersion', '')
+
         family_id = request_dict.get('familyId', None)
         room_id = request_dict.get('roomId', 0)
 
@@ -93,7 +107,11 @@ class GatewaySubDeviceView(View):
             with transaction.atomic():
                 sub_device = GatewaySubDevice.objects.create(device_id=device_id, device_type=device_type,
                                                              nickname=nickname, ieee_addr=ieee_addr, src_addr=src_addr,
-                                                             status=1, created_time=now_time, updated_time=now_time)
+                                                             status=1, mac=mac, device_model=device_model,
+                                                             manufacturer=manufacturer, sensor_serial=sensor_serial,
+                                                             firmware_version=firmware_version,
+                                                             hardware_version=hardware_version,
+                                                             created_time=now_time, updated_time=now_time)
                 FamilyRoomDevice.objects.create(family_id=family_id, room_id=room_id, device_id=device_id,
                                                 sub_device=sub_device.id, created_time=now_time, updated_time=now_time)
             return response.json(0)
@@ -101,32 +119,29 @@ class GatewaySubDeviceView(View):
             return response.json(500, repr(e))
 
     @staticmethod
-    def query(request_dict, user_id, response):
+    def query_sub_device(request_dict, response):
         """
-        查询子设备
+        查询子设备信息
         @param request_dict: 请求参数
-        @request_dict serial_number: 序列号
-        @param user_id: 用户id
+        @request_dict gatewaySubId: 子设备id
         @param response: 响应对象
         @return: response
         """
-        serial_number = request_dict.get('serialNumber', None)
+        sub_device_id = request_dict.get('gatewaySubId', None)
 
-        if not all([serial_number]):
+        if not all([sub_device_id]):
             return response.json(444)
         try:
-            device_info_qs = Device_Info.objects.filter(userID_id=user_id, serial_number=serial_number).values('id')
-            if not device_info_qs.exists():
-                return response.json(14)
-            device_id = device_info_qs[0]['id']
-            count = GatewaySubDevice.objects.filter(device_id=device_id).count()
-            gateway_sub_device_qs = GatewaySubDevice.objects.filter(device_id=device_id).values('device_type',
-                                                                                                'nickname', 'ieee_addr',
-                                                                                                'src_addr', 'status')
-            gateway_sub_device_list = [gateway_sub_device for gateway_sub_device in gateway_sub_device_qs]
+            gateway_sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('manufacturer',
+                                                                                             'device_model',
+                                                                                             'mac', 'sensor_serial')
+            if not gateway_sub_device_qs.exists():
+                return response.json(173)
             res = {
-                'count': count,
-                'gateway_sub_device_list': gateway_sub_device_list
+                'manufacturer': gateway_sub_device_qs[0]['manufacturer'],
+                'device_model': gateway_sub_device_qs[0]['device_model'],
+                'mac': gateway_sub_device_qs[0]['mac'],
+                'sensor_serial': gateway_sub_device_qs[0]['sensor_serial'],
             }
             return response.json(0, res)
         except Exception as e:

+ 74 - 35
Controller/TestApi.py

@@ -56,10 +56,7 @@ from Service.CommonService import CommonService
 from Service.ModelService import ModelService
 from Object.m3u8generate import PlaylistGenerator
 from Model.models import Device_User, Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidPushModel
-from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL,PAYPAL_WEB_HOOK_ID
-
-
-
+from Ansjer.config import PAYPAL_CRD, SERVER_DOMAIN, SERVER_DOMAIN_SSL, PAYPAL_WEB_HOOK_ID
 
 SERVER_DOMAIN = 'http://test.dvema.com/'
 ACCESS_KEY = "AKIA2E67UIMD3CYTIWPA"
@@ -86,7 +83,7 @@ class testView(View):
         request.encoding = 'utf-8'
         operation = kwargs.get('operation')
         response = ResponseObject()
-        return response.json(0,request.body)
+        return response.json(0, request.body)
 
     def validation(self, request_dict, request, operation):
         response = ResponseObject()
@@ -97,7 +94,7 @@ class testView(View):
             logger = logging.getLogger('info')
             logger.info('测试打印')
             res = make_password(123456)
-            return JsonResponse(status=200, data=res,safe=False)
+            return JsonResponse(status=200, data=res, safe=False)
         elif operation == 'testMiddleWare':
             a = int('a')
             return JsonResponse(status=200, safe=False)
@@ -126,13 +123,13 @@ class testView(View):
             return self.queryInterface(request_dict, userID, response)
         elif operation == 'generateToken':
             userID = '158943604783713800138000'
-            return self.generate_token(request_dict,userID)
+            return self.generate_token(request_dict, userID)
         elif operation == 'test_upload_s3':
             userID = '158943604783713800138000'
             return self.test_upload_s3(request_dict, response)
         elif operation == 'rekognition':
             userID = '158943604783713800138000'
-            return self.testRekognition(request,request_dict)
+            return self.testRekognition(request, request_dict)
         elif operation == 'ip':
             return self.ip(response)
         elif operation == 'configType':
@@ -141,10 +138,32 @@ class testView(View):
             return self.createData(request_dict, response)
         elif operation == 'findPaypalOrder':
             return self.findPaypalOrder(request_dict, response)
+        elif operation == 'comb':
+            return self.do_comb(request_dict, response)
+        elif operation == 'count_ts':
+            return self.count_ts(request_dict, response)
         else:
             return 123
 
-    def findPaypalOrder(self,request_dict, response):
+    def do_comb(self, request_dict, response):
+        import itertools
+        list1 = [1, 2, 3, 4]
+        list2 = []
+        for i in range(1, len(list1) + 1):
+            iter = itertools.combinations(list1, i)
+            list2.append(list(iter))
+        list3 = []
+        for list_ in list2:
+            for val in list_:
+                print('-------------list')
+                print(type(val))
+                comb = [str(i) for i in val]
+                comb_int = int("".join(comb))
+                list3.append(comb_int)
+
+        return HttpResponse(json.dumps(list3))
+
+    def findPaypalOrder(self, request_dict, response):
         from paypalrestsdk import Order, ResourceNotFound
         PAYPAL_CRD = {
             "mode": "sandbox",  # sandbox or live
@@ -178,11 +197,9 @@ class testView(View):
         # print(related_resources)
         # return HttpResponse(sale)
 
-
-
     def createBucket(self):
 
-        #查看桶列表
+        # 查看桶列表
         # url = "https://azvod1.s3-ap-northeast-1.amazonaws.com"
         # session = Session(ACCESS_KEY, SECRET_KEY)
         # s3_client = session.client('s3', endpoint_url=url)
@@ -193,10 +210,10 @@ class testView(View):
         session = Session(ACCESS_KEY, SECRET_KEY)
         s3_client = session.client('s3')
 
-        #上传
+        # 上传
         # s3_client.put_object(Bucket="azvod1", Key="file/rule.txt", Body=open(r"E:\download\Shadowsocks-4.1.10.0\user-rule.txt", 'rb').read())
 
-        #下载
+        # 下载
         resp = s3_client.get_object(Bucket="azvod1", Key="file/rule.txt")
         with open('local.txt', 'wb') as f:
             f.write(resp['Body'].read())
@@ -219,7 +236,7 @@ class testView(View):
         if uid:
             dvqs = dvqs.filter(UID=uid)
         # count = dvqs.count()
-        #分页
+        # 分页
         dvql = dvqs[(page - 1) * line:page * line].values('id', 'userID', 'NickName', 'UID', 'View_Account',
                                                           'View_Password', 'ChannelIndex', 'Type', 'isShare',
                                                           'primaryUserID', 'primaryMaster', 'data_joined',
@@ -273,8 +290,7 @@ class testView(View):
             data.append(p)
         return response.json(0, data)
 
-
-    #获取播放列表
+    # 获取播放列表
     def do_test_query_vod_list(self, userID, ip, request_dict, response):
         uid = 'GZL2PEFJPLY7W6BG111A'
         channel = 2
@@ -315,7 +331,7 @@ class testView(View):
             'sec': 12})
         return response.json(0, vod_play_list)
 
-    #生成m3u8列表
+    # 生成m3u8列表
     def do_sign_play_m3u8(self, request_dict, response):
         uid = 'GZL2PEFJPLY7W6BG111A'
         channel = 2
@@ -653,9 +669,6 @@ class testView(View):
                 return HttpResponse(json.dumps(res, ensure_ascii=False),
                                     content_type="application/json,charset=utf-8")
 
-
-
-
     def do_pay_by_ali(self, request_dict, userID, response):
         uid = request_dict.get('uid', None)
         rank = request_dict.get('rank', None)
@@ -755,24 +768,23 @@ class testView(View):
             vod_play_list.append({'name': vod['time'], 'sign_url': vod_play_url, 'thumb': thumb, 'sec': vod['sec']})
         return response.json(0, vod_play_list)
 
-    def generate_token(self,request_dict,userID):
+    def generate_token(self, request_dict, userID):
         # UserIdToken
         tko = TokenObject()
-        userID = request_dict.get('userID',None)
-        username = request_dict.get('username',None)
+        userID = request_dict.get('userID', None)
+        username = request_dict.get('username', None)
         res = tko.generate(
             data={'userID': userID, 'lang': 'cn', 'user': username, 'm_code': username})
-        #uidToken
+        # uidToken
         # utko = UidTokenObject()
         # res = utko.generate(data={'uid': '4UZSEDP93MJ3X7YB111A','channel': 1})
 
         # from Object.ETkObject import ETkObject
         # etkObj = ETkObject(etk='')
         # res = etkObj.encrypt("4UZSEDP93MJ3X7YB111A")
-        return JsonResponse(status=200, data=res,safe=False)
-
+        return JsonResponse(status=200, data=res, safe=False)
 
-    def test_upload_s3(self,request_dict , response):
+    def test_upload_s3(self, request_dict, response):
         aws_s3_guonei = boto3.client(
             's3',
             aws_access_key_id=AWS_ACCESS_KEY_ID[0],
@@ -791,8 +803,7 @@ class testView(View):
         )
         return response.json(0, {'datas': response_url, 'count': 1})
 
-
-    def testRekognition(self,request,request_dict):
+    def testRekognition(self, request, request_dict):
         # ip = CommonService.get_ip_address(request)
         # ipInfo = CommonService.getIpIpInfo(ip,"CN")
         # # print(type(ipInfo))
@@ -807,15 +818,15 @@ class testView(View):
         # client = boto3.client('s3', aws_access_key_id='AKIA2E67UIMD45Y3HL53',aws_secret_access_key='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',region_name='us-east-1')
         # exit(request.FILES)
 
-
         files = request.FILES.get('image')
-        labels = int(request_dict.get('labels',5))
-        minConfidence = int(request_dict.get('minConfidence',99))
+        labels = int(request_dict.get('labels', 5))
+        minConfidence = int(request_dict.get('minConfidence', 99))
         if not files:
             return HttpResponse('请上传图片!!!!')
-        client = boto3.client('rekognition', aws_access_key_id='AKIA2E67UIMD6JD6TN3J',aws_secret_access_key='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',region_name='us-east-1')
+        client = boto3.client('rekognition', aws_access_key_id='AKIA2E67UIMD6JD6TN3J',
+                              aws_secret_access_key='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', region_name='us-east-1')
         # image = open('E:/photo/a615fa40b8c476bab0f6eeb332e62a5a-1000.jpg', "rb")
-        response = client.detect_labels(Image={'Bytes':files.read()},MaxLabels=labels,MinConfidence=minConfidence)
+        response = client.detect_labels(Image={'Bytes': files.read()}, MaxLabels=labels, MinConfidence=minConfidence)
         # for obj in response['Labels']:
         #     exit(obj)
         #     if obj['Name'] == 'Person':
@@ -839,3 +850,31 @@ class testView(View):
         # qs = DeviceLogModel.objects.filter(add_time__lt=filter_date)
         DeviceLogModel.objects.create(uid=uid)
         return response.json(0)
+
+    def count_ts(self, request_dict, response):
+        year = request_dict.get('year', None)
+        month = request_dict.get('month', None)
+        if not year:
+            year = CommonService.timestamp_to_str(int(time.time()), '%Y')
+        if not month:
+            month = CommonService.timestamp_to_str(int(time.time()), '%m')
+        year = int(year)
+        month = int(month)
+        startTime = CommonService.str_to_timestamp('{year}-{month}'.format(year=year, month=month), '%Y-%m')
+        endTime = CommonService.str_to_timestamp('{year}-{month}'.format(year=year, month=month + 1), '%Y-%m') - 1
+        qsTs = VodHlsModel.objects.filter(time__gte=startTime, time__lte=endTime).values('fg')
+        if not qsTs.exists():
+            return HttpResponse('查无数据')
+        sumTs = 0  # 总ts个数
+        sumSec = 0  # 总秒数
+        for val in qsTs:
+            fg = int(val['fg'])
+            sumTs += fg & 0xf
+            for i in range(15):
+                shift = (i + 1) * 4
+                sumSec += (fg >> shift) & 0xf
+        size = 0
+        return HttpResponse(
+            "{year}年{month}月 </br>上传的TS总数:{sumTs} </br> 总秒数:{sumSec} </br> 总大小:{size}GB (1秒约等150KB计算)".format(year=year, month=month,
+                                                                                           sumTs=sumTs, sumSec=sumSec,
+                                                                                           size=size))

+ 233 - 10
Controller/UnicomCombo/UnicomComboController.py

@@ -7,10 +7,18 @@
 @Software: PyCharm
 """
 import json
+import logging
+import time
 
+from django.db import transaction
 from django.http import HttpResponse
 from django.views.generic.base import View
 
+from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Object.UnicomObject import UnicomObjeect
+
 
 class UnicomComboView(View):
     def get(self, request, *args, **kwargs):
@@ -24,18 +32,233 @@ class UnicomComboView(View):
         return self.validation(request.POST, request, operation)
 
     def validation(self, request_dict, request, operation):
-        if operation == 'test':
-            return self.test(request_dict, request)
+        if operation == 'buy-notify':
+            return self.package_callback_notify(request_dict, request)
+        elif operation == 'device-queue-monitoring':
+            return self.device_queue_monitoring_push(request_dict, request)
+        elif operation == 'device-status-change':
+            return self.device_status_change_push(request_dict, request)
+        elif operation == 'device-bind':
+            response = ResponseObject('cn')
+            return self.device_add(request_dict, response)
         else:
+            token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+            lang = request_dict.get('lang', token.lang)
+            response = ResponseObject(lang)
+            if token.code != 0:
+                return response.json(token.code)
+            if operation == 'combo-save':
+                return self.save_unicom_combo(request_dict, response)
+            elif operation == 'combo-list':
+                return self.query_package_list(response)
+
+    @classmethod
+    def device_add(cls, request_dict, response):
+        """
+        设备绑定iccid
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        iccid = request_dict.get('iccid', None)
+        serial_no = request_dict.get('serialNo', None)
+        if not all([iccid, serial_no]):
+            return response.json(444)
+        n_time = int(time.time())
+        try:
+            with transaction.atomic():
+                # 待完善代码 根据uid与用户id验证系统设备
+                unicom_device_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
+                if unicom_device_qs.exists():
+                    return response.json(174)
+                unicom_obj = UnicomObjeect()
+                result = unicom_obj.verify_device(iccid=iccid)
+                if result.status_code == 200 and result.text:
+                    res_dict = json.loads(result.text)
+                    if res_dict['success']:
+                        if res_dict['data']['status'] == 0:
+                            return response.json(173)
+                        params = {'iccid': iccid, 'serial_no': serial_no, 'updated_time': n_time,
+                                  'created_time': n_time}
+                        UnicomDeviceInfo.objects.create(**params)
+                    return response.json(0)
+                else:
+                    return response.json(173)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def save_unicom_combo(cls, request_dict, response):
+        """
+        联通套餐保存
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        combo_id = request_dict.get('id', None)
+        combo_name = request_dict.get('comboName', None)
+        flow_total = request_dict.get('flowTotal', None)
+        expiration_days = request_dict.get('expirationDays', None)
+        expiration_type = request_dict.get('expirationType', None)
+        price = request_dict.get('price', None)
+        remark = request_dict.get('remark', None)
+        pay_type = request_dict.get('payType', '').split(',')
+        if not all([pay_type, combo_name, flow_total, expiration_days, expiration_type, price]):
+            return response.json(444)
+        try:
+            flow_total = int(flow_total)
+            expiration_days = int(expiration_days)
+            expiration_type = int(expiration_type)
+            with transaction.atomic():
+                re_data = {
+                    'combo_name': combo_name,
+                    'flow_total': flow_total,
+                    'expiration_days': expiration_days,
+                    'expiration_type': expiration_type,
+                    'price': price,
+                }
+                if remark:
+                    re_data['remark'] = remark
+                if combo_id:
+                    UnicomCombo.objects.filter(id=combo_id).update(**re_data)
+                    UnicomCombo.objects.get(id=combo_id).pay_type.set(pay_type)
+                    return response.json(0)
+                UnicomCombo.objects.create(**re_data).pay_type.set(pay_type)
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def query_package_list(cls, response):
+        """
+        查询套餐列表
+        @return:
+        """
+        try:
+            combo_qs = UnicomCombo.objects.filter(is_show=1, status=0, is_del=False) \
+                .order_by('sort').values('id', 'combo_name',
+                                         'flow_total',
+                                         'expiration_days',
+                                         'expiration_type', 'price',
+                                         'remark')
+            if not combo_qs.exists():
+                return response.json(0, [])
+            combo_list = []
+            for item in combo_qs:
+                # 获取支付方式列表
+                pay_type_qs = Pay_Type.objects.filter(unicomcombo=item['id']).values('id', 'payment')
+                combo_list.append({
+                    'id': item['id'],
+                    'comboName': item['combo_name'],
+                    'flowTotal': item['flow_total'],
+                    'expirationDays': item['expiration_days'],
+                    'expirationType': item['expiration_type'],
+                    'price': item['price'],
+                    'remark': item['remark'],
+                    'payTypes': list(pay_type_qs),
+                })
+            return response.json(0, combo_list)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def buy_package(cls):
+        """
+        购买套餐
+        @return:
+        """
+        pass
+
+    @classmethod
+    def query_device_usage_history(cls):
+        """
+        查询用量历史
+        @return:
+        """
+
+    @staticmethod
+    def package_callback_notify(request_dict, request):
+        """
+        异步套餐订购回调
+        @param request_dict:
+        @param request:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            logger.info('联通异步套餐订购回调参数{}'.format(request_dict))
+            body = request.body.decode("utf-8")
+            if body:
+                dict_data = json.loads(body)
+                sign = dict_data['sign']
+                logger.info('设备订购异步回调请求参数{}'.format(dict_data))
+                dict_data.pop('sign')
+                unicom_obj = UnicomObjeect()
+                generate_sign = unicom_obj.createSign(**dict_data)
+                logger.info('设备订购请求签名{}'.format(sign))
+                logger.info('设备订购生成签名{}'.format(generate_sign))
+            r_data = {'success': True, 'msg': '成功'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+        except Exception as e:
+            print(repr(e))
             r_data = {'success': False, 'msg': '失败'}
             return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
 
     @staticmethod
-    def test(request_dict, request):
-        body = request.body.decode("utf-8")
-        if body:
-            dict_data = json.loads(body)
-            print(dict_data)
-        print(request_dict)
-        r_data = {'success': True, 'msg': '成功'}
-        return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+    def device_queue_monitoring_push(request_dict, request):
+        """
+        设备套餐队列用完或者到期推送
+        @param request_dict:
+        @param request:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            logger.info('设备套餐队列推送{}'.format(request_dict))
+            body = request.body.decode("utf-8")
+            if body:
+                dict_data = json.loads(body)
+                sign = dict_data['sign']
+                logger.info('设备套餐队列回调请求参数{}'.format(dict_data))
+                dict_data.pop('sign')
+                unicom_obj = UnicomObjeect()
+                generate_sign = unicom_obj.createSign(**dict_data)
+                logger.info('设备套餐队列请求签名{}'.format(sign))
+                logger.info('设备套餐队列生成签名{}'.format(generate_sign))
+            r_data = {'success': True, 'msg': '成功'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+        except Exception as e:
+            print(repr(e))
+            r_data = {'success': False, 'msg': '失败'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+
+    @staticmethod
+    def device_status_change_push(request_dict, request):
+        """
+        设备状态变更推送执行场景说明
+        @param request_dict:
+        @param request:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            logger.info('设备状态变更推送{}'.format(request_dict))
+            body = request.body.decode("utf-8")
+            if body:
+                dict_data = json.loads(body)
+                sign = dict_data['sign']
+                logger.info('设备状态变更推送请求参数{}'.format(dict_data))
+                dict_data.pop('sign')
+                unicom_obj = UnicomObjeect()
+                generate_sign = unicom_obj.createSign(**dict_data)
+                logger.info('设备状态变更推送请求签名{}'.format(sign))
+                logger.info('设备状态变更推送生成签名{}'.format(generate_sign))
+            r_data = {'success': True, 'msg': '成功'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+        except Exception as e:
+            print(repr(e))
+            r_data = {'success': False, 'msg': '失败'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")

+ 106 - 1
Model/models.py

@@ -892,7 +892,8 @@ class Order_Model(models.Model):
     rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='关联云存套餐表')
     ai_rank = models.ForeignKey(AiStoreMeal, to_field='id', default='', on_delete=models.CASCADE,
                                 verbose_name='关联ai套餐表')
-    order_type = models.SmallIntegerField(default=0, verbose_name='订单类型:0:云存:1:ai')
+    order_type = models.SmallIntegerField(default=0, verbose_name='订单类型:0:云存,1:ai,2:联通4G')
+    unify_combo_id = models.CharField(blank=True, default='', max_length=32, verbose_name=u'统一套餐id')
     nickname = models.CharField(default='', max_length=64, verbose_name='设备昵称')
     uid_bucket_id = models.IntegerField(default=0, verbose_name='关联uid_bucket的字段')
     commodity_type = models.SmallIntegerField(default=0, verbose_name='云存储套餐类型')
@@ -2537,6 +2538,13 @@ class GatewaySubDevice(models.Model):
     ieee_addr = models.CharField(default='', max_length=64, verbose_name=u'长地址')
     src_addr = models.CharField(default='', max_length=16, verbose_name=u'短地址')
     status = models.SmallIntegerField(default=0, verbose_name='状态')  # 0:关闭, 1:开启
+    is_tampered = models.SmallIntegerField(default=0, verbose_name='拆动状态')  # 0:正常, 1:被拆动
+    mac = models.CharField(default='', max_length=32, verbose_name=u'mac地址')
+    device_model = models.CharField(default='', max_length=16, verbose_name=u'设备型号')
+    manufacturer = models.CharField(default='', max_length=16, verbose_name=u'制造商')
+    sensor_serial = models.CharField(default='', max_length=32, verbose_name=u'传感器序列号')
+    firmware_version = models.CharField(default='', max_length=32, verbose_name=u'固件版本')
+    hardware_version = models.CharField(default='', max_length=32, verbose_name=u'硬件版本')
     created_time = models.IntegerField(default=0, verbose_name='创建时间')
     updated_time = models.IntegerField(default=0, verbose_name='更新时间')
 
@@ -2594,3 +2602,100 @@ class SensorRecord(models.Model):
         verbose_name_plural = verbose_name
         app_label = 'PushModel'
 
+
+class UnicomCombo(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    package_id = models.CharField(default='', max_length=32, verbose_name=u'联通套餐id')
+    combo_name = models.CharField(default='', max_length=32, verbose_name=u'套餐名称')
+    status = models.SmallIntegerField(default=0, verbose_name='状态{0:开启,1:停用}')
+    flow_total = models.IntegerField(default=0, blank=True, verbose_name=u'流量总量值 单位(MB)')
+    expiration_days = models.IntegerField(default=0, blank=True, verbose_name=u'有效期天数')
+    expiration_type = models.SmallIntegerField(default=0, verbose_name=u'有效期类型,0=天,1=月,2=年')
+    pay_type = models.ManyToManyField(to='Pay_Type', verbose_name='付款类型', db_table='unicom_combo_pay_type')
+    price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
+    sort = models.IntegerField(default=0, blank=True, verbose_name=u'排序,越小越靠前')
+    remark = models.TextField(blank=True, default='', verbose_name=u'描述信息')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    is_show = models.SmallIntegerField(default=1, verbose_name=u'是否显示,0:不显示,1:显示')
+    is_del = models.BooleanField(blank=True, default=False, verbose_name=u'是否删除默认false')
+
+    class Meta:
+        db_table = 'unicom_combo'
+        verbose_name = '联通套餐表'
+        verbose_name_plural = verbose_name
+
+
+class UnicomComboOrderInfo(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    renew_list_id = models.CharField(default='', max_length=32, verbose_name=u'联通订购成功套餐队列id')
+    status = models.SmallIntegerField(default=0, verbose_name='状态{0:未使用,1:已使用,2:已过期}')
+    orders = models.ForeignKey(Order_Model, to_field='orderID', default='', on_delete=models.CASCADE,
+                               verbose_name='关联订单表')
+    combo = models.ForeignKey(UnicomCombo, to_field='id', default='', on_delete=models.CASCADE,
+                              verbose_name=u'联通套餐表')
+    activation_time = models.IntegerField(default=0, verbose_name='激活时间')
+    expire_time = models.IntegerField(default=0, verbose_name='过期时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    is_del = models.BooleanField(blank=True, default=False, verbose_name=u'是否删除')
+
+    class Meta:
+        db_table = 'unicom_combo_order_info'
+        verbose_name = '联通套餐订单信息表'
+        verbose_name_plural = verbose_name
+
+
+class UnicomDeviceInfo(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    serial_no = models.CharField(default='', max_length=32, verbose_name=u'设备序列号')
+    user_id = models.CharField(blank=True, max_length=32, verbose_name=u'用户id')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'unicom_device_info'
+        verbose_name = '联通设备信息'
+        verbose_name_plural = verbose_name
+
+
+class UnicomDeviceQueueMonitoringPush(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    serial_no = models.CharField(default='', max_length=32, verbose_name=u'序列号')
+    sign = models.CharField(default='', max_length=32, verbose_name=u'验证签名')
+    time = models.CharField(default='', max_length=32, verbose_name=u'推送时间(yyyymmddhhmiss)')
+    type = models.CharField(default='', max_length=32, verbose_name=u'推送类型:DEVICE_QUEUE_MONITORING:设队列监控;')
+    current_renew_list_id = models.CharField(default='', max_length=32, verbose_name=u'队列ID')
+    no_queue_available = models.SmallIntegerField(default=0, verbose_name=u'是否无可用队列;1:是;0:否')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'unicom_device_queue_monitoring_push'
+        verbose_name = '联通设备队列监控推送表'
+        verbose_name_plural = verbose_name
+
+
+class UnicomDeviceStatusChangePush(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    serial_no = models.CharField(default='', max_length=32, verbose_name=u'序列号')
+    sign = models.CharField(default='', max_length=32, verbose_name=u'验证签名')
+    time = models.CharField(default='', max_length=32, verbose_name=u'推送时间(yyyymmddhhmiss)')
+    # 变更类型: DEVICE_REAL_NAME_STATUS_CHANGE:实名状态变更;DEVICE_STATUS_CHANGE:设备状态变更;
+    type = models.CharField(default='', max_length=32, verbose_name=u'变更类型')
+    # 之前值:设备状态变更 1: 已激活;2: 可激活;3: 已停用;4: 已失效;5: 可测试;6: 库存;7: 已更换;8: 已清除;
+    previous_val = models.CharField(default='', max_length=32, verbose_name=u'之前值:')
+    # 当前值:设备状态变更 1:已激活;2:可激活;3:已停用;4:已失效;5:可测试;6:库存;7:已更换;8:已清除;
+    current_val = models.CharField(default='', max_length=32, verbose_name=u'当前值:')
+    reason = models.SmallIntegerField(default=0, verbose_name=u'变更原因编码:请查看【信息提示码】')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'unicom_device_status_change_push'
+        verbose_name = '联通设备状态变更推送表'
+        verbose_name_plural = verbose_name

+ 256 - 0
Object/UnicomObject.py

@@ -0,0 +1,256 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UnicomObject.py
+@Time    : 2022/6/17 11:03
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import base64
+import json
+
+import requests
+from Crypto.Cipher import AES
+from decimal import Decimal
+from Object.utils import SM3Util
+
+from Ansjer.config import unicomAppUrl, unicomAppId, unicomAppSecret, unicomTenantId, \
+    unicomEncodeKey, unicomIvKey, unicomUserName, unicomPassword, unicomPushKey
+from Object.utils.SymmetricCryptoUtil import AESencrypt
+
+"""
+联通4Gapi
+具体参数查看接口文档
+https://www.showdoc.com.cn/unicomJYHapi/8158648460007467
+"""
+
+
+class UnicomObjeect:
+    def __init__(self):
+        self.appUrl = unicomAppUrl
+        self.appId = unicomAppId
+        self.appSecret = unicomAppSecret
+        self.tenantId = unicomTenantId
+        self.encodeKey = unicomEncodeKey
+        self.ivKey = unicomIvKey
+        self.username = unicomUserName
+        self.password = unicomPassword
+        self.pushKey = unicomPushKey
+        self.headers = {'Tenant': self.tenantId, 'content-type': 'application/x-www-form-urlencoded'}
+
+    # pip install snowland-smx
+    def createSign(self, reverse=False, **sign_params):
+        """
+        调用接口(API)时需要对请求参数进行签名(sign)验证,
+        算法:
+        根据参数名称将你的所有请求参数按照字母先后顺序排序: key = value & key = value,对除签名外的所有请求参数按
+        key
+        做的升序排列。
+        如:将
+        foo = 1, bar = 2, baz = 3
+        排序为
+        bar = 2, baz = 3, foo = 1
+        参数名和参数值链接后,得到拼装字符串(注意:参数名与参数值左右两边不能包含空格)
+        bar = 2 & baz = 3 & foo = 1
+        将
+        pushkey拼接到参数字符尾部进行
+        SM3
+        加密,再转化成大写,格式是
+        (SM3(key1=value1 & key2=value2 &...& key= pushKey)).upcase
+        @param reverse:
+        @param sign_params:
+        @return:
+        """
+        dict_2 = dict(sorted(sign_params.items(), key=lambda item: item[0], reverse=reverse))
+        data_list = []
+        for item in dict_2.items():
+            if item[0] and item[1]:
+                data_list.append("{}={}".format(item[0], item[1]))
+        val = '&'.join(data_list)
+        push_key = '&key={}'.format(self.pushKey)
+        val = val + push_key
+        return SM3Util.Hash_sm3(val).upper()
+
+    def get_login_authorization(self):
+        """
+        获取登录授权
+        注意登录认证Authorization和登录后的请求认证不一样
+        算法:appId+":"+appSecret base64转码生成 前面加Basic
+        @return: "Basic " + base64_data
+        """
+        voucher = self.appId + ':' + self.appSecret
+        base64_data = str(base64.b64encode(voucher.encode("utf-8")), "utf-8")
+        return "Basic " + base64_data
+
+    def get_encode_password(self):
+        """
+        获取对称加密
+        @return: encrypt_pwd
+        """
+        aes = AESencrypt(self.encodeKey.encode('utf-8'), AES.MODE_CBC, self.ivKey.encode('utf-8'),
+                         paddingMode="ZeroPadding",
+                         characterSet='utf-8')
+        encrypt_pwd = aes.encryptFromString(self.password)
+        return encrypt_pwd
+
+    def generate_token(self):
+        """
+        生成令牌
+        @return: token
+        """
+        url = self.appUrl + '/auc/oauth/token'
+        pwd = self.get_encode_password()
+        body = {'username': self.username, 'password': pwd, 'grant_type': 'password', 'scope': 'server'}
+        headers = self.headers
+        headers['Authorization'] = self.get_login_authorization()
+        response_data = requests.post(url, data=body, headers=headers)
+        response_data = json.loads(response_data.text)
+        return response_data['access_token']
+
+    def refresh_token(self, refresh_token):
+        """
+        刷新令牌
+        @param refresh_token:
+        @return:
+        """
+        url = self.appUrl + '/auc/oauth/token?grant_type=refresh_token'
+        body = {'refresh_token': refresh_token, 'grant_type': 'refresh_token'}
+        headers = self.headers
+        headers['Authorization'] = self.get_login_authorization()
+        response_data = requests.post(url, data=body, headers=headers)
+        return response_data.text
+
+    def business_unify_headers(self):
+        """
+        业务统一headers
+        在请求头中增加key为Authorization,value为"Bearer " + token
+        @return: headers
+        """
+        token = self.generate_token()
+        headers = self.headers
+        headers['Authorization'] = 'Bearer ' + token
+        return headers
+
+    # 业务api  注意 get与post 请求数据类型不同 post使用:application/json
+    def verify_device(self, **re_params):
+        """
+        验证设备
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/verify-device'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def query_device_status(self, **re_params):
+        """
+        查询设备状态
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/device-status'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def update_device_state(self, **re_data):
+        """
+        修改设备状态
+        @param re_data:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/device-state'
+        headers = self.business_unify_headers()
+        headers['content-type'] = 'application/json'
+        return requests.post(url, data=json.dumps(re_data), headers=headers)
+
+    def query_device_usage_history(self, **re_params):
+        """
+        查询设备用量历史
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/usage/device-usage-history'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def query_current_renew_list_usage_details(self, **re_params):
+        """
+        查询设备当前队列用量详情
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/usage/current-renewlist-usage-details'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def get_device_batch_detail(self, **re_data):
+        """
+        查询设备当前队列用量详情
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/batch-detail'
+        headers = self.business_unify_headers()
+        headers['content-type'] = 'application/json'
+        return requests.post(url, data=json.dumps(re_data), headers=headers)
+
+    def query_package_list(self, **re_params):
+        """
+        查询套餐列表
+        @return:
+        """
+        url = self.appUrl + '/platform/api/package/list'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def query_renewal_list(self, **re_params):
+        """
+        续费套餐列表
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/package/list'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def async_buy_package(self, **re_data):
+        """
+        查询设备当前队列用量详情
+        @return:
+        """
+        url = self.appUrl + '/platform/api/package/async-buy-package'
+        headers = self.business_unify_headers()
+        headers['content-type'] = 'application/json'
+        return requests.post(url, data=json.dumps(re_data), headers=headers)
+
+
+if __name__ == '__main__':
+    price = '12.13'
+    print(float(price))
+    discount = '6'
+    dd = Decimal(price) - Decimal(discount)
+    print(dd.quantize(Decimal('0.00')))
+
+    unicom_api = UnicomObjeect()
+    data = {'foo': 1, 'bar': 2, 'baz': 3}
+    print(unicom_api.createSign(**data))
+    # result = unicom_api.generate_token()
+    # result = unicom_api.refresh_token('5d0c0f30-99bd-4f17-9614-3524495b05d4')
+    params = {'iccid': '89860620170009628001'}
+    response = unicom_api.verify_device(**params)
+    # response = unicom_api.query_device_status(**params)
+    # response = unicom_api.update_device_state(**params)
+    # response = unicom_api.query_device_usage_history(**params)
+    # response = unicom_api.query_current_renew_list_usage_details(**params)
+    # unicom_api.get_device_batch_detail()
+    # response = unicom_api.query_package_list(**params)
+    # response = unicom_api.query_renewal_list(**params)
+
+    if response.status_code == 200:
+        res_dict = json.loads(response.text)
+        print(res_dict)
+    response_json = {
+        "success": True,
+        "msg": "操作成功",
+        "code": 0,
+        "data": {
+            "iccid": "8986062018007784202",
+            "completeIccid": "89860620180077842020",
+            "status": 1
+        }
+    }
+    print(response_json['data']['iccid'])
+    print(response.status_code)

+ 237 - 0
Object/utils/SM3Util.py

@@ -0,0 +1,237 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : SM3Util.py
+@Time    : 2022/6/28 8:34
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+# -*- encoding: utf-8 -*-
+"""
+@File    : SM32.py
+@Time    : 2022/6/28 9:49
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+from math import ceil
+
+IV = "7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e"
+IV = int(IV.replace(" ", ""), 16)
+a = []
+for i in range(0, 8):
+    a.append(0)
+    a[i] = (IV >> ((7 - i) * 32)) & 0xFFFFFFFF
+IV = a
+
+
+def out_hex(list1):
+    for i in list1:
+        print("%08x" % i)
+    print("\n")
+
+
+def rotate_left(a, k):
+    k = k % 32
+    return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32 - k))
+
+
+T_j = []
+for i in range(0, 16):
+    T_j.append(0)
+    T_j[i] = 0x79cc4519
+for i in range(16, 64):
+    T_j.append(0)
+    T_j[i] = 0x7a879d8a
+
+
+def FF_j(X, Y, Z, j):
+    if 0 <= j < 16:
+        ret = X ^ Y ^ Z
+    elif 16 <= j < 64:
+        ret = (X & Y) | (X & Z) | (Y & Z)
+    return ret
+
+
+def GG_j(X, Y, Z, j):
+    if 0 <= j < 16:
+        ret = X ^ Y ^ Z
+    elif 16 <= j < 64:
+        # ret = (X | Y) & ((2 ** 32 - 1 - X) | Z)
+        ret = (X & Y) | ((~ X) & Z)
+    return ret
+
+
+def P_0(X):
+    return X ^ (rotate_left(X, 9)) ^ (rotate_left(X, 17))
+
+
+def P_1(X):
+    return X ^ (rotate_left(X, 15)) ^ (rotate_left(X, 23))
+
+
+def CF(V_i, B_i):
+    W = []
+    for i in range(16):
+        weight = 0x1000000
+        data = 0
+        for k in range(i * 4, (i + 1) * 4):
+            data = data + B_i[k] * weight
+            weight = int(weight / 0x100)
+        W.append(data)
+
+    for j in range(16, 68):
+        W.append(0)
+        W[j] = P_1(W[j - 16] ^ W[j - 9] ^ (rotate_left(W[j - 3], 15))) ^ (rotate_left(W[j - 13], 7)) ^ W[j - 6]
+        str1 = "%08x" % W[j]
+    W_1 = []
+    for j in range(0, 64):
+        W_1.append(0)
+        W_1[j] = W[j] ^ W[j + 4]
+        str1 = "%08x" % W_1[j]
+
+    A, B, C, D, E, F, G, H = V_i
+    """
+    print "00",
+    out_hex([A, B, C, D, E, F, G, H])
+    """
+    for j in range(0, 64):
+        SS1 = rotate_left(((rotate_left(A, 12)) + E + (rotate_left(T_j[j], j))) & 0xFFFFFFFF, 7)
+        SS2 = SS1 ^ (rotate_left(A, 12))
+        TT1 = (FF_j(A, B, C, j) + D + SS2 + W_1[j]) & 0xFFFFFFFF
+        TT2 = (GG_j(E, F, G, j) + H + SS1 + W[j]) & 0xFFFFFFFF
+        D = C
+        C = rotate_left(B, 9)
+        B = A
+        A = TT1
+        H = G
+        G = rotate_left(F, 19)
+        F = E
+        E = P_0(TT2)
+
+        A = A & 0xFFFFFFFF
+        B = B & 0xFFFFFFFF
+        C = C & 0xFFFFFFFF
+        D = D & 0xFFFFFFFF
+        E = E & 0xFFFFFFFF
+        F = F & 0xFFFFFFFF
+        G = G & 0xFFFFFFFF
+        H = H & 0xFFFFFFFF
+        """
+        str1 = "%02d" % j
+        if str1[0] == "0":
+            str1 = ' ' + str1[1:]
+        print str1,
+        out_hex([A, B, C, D, E, F, G, H])
+        """
+
+    V_i_1 = [A ^ V_i[0], B ^ V_i[1], C ^ V_i[2], D ^ V_i[3], E ^ V_i[4], F ^ V_i[5], G ^ V_i[6], H ^ V_i[7]]
+    return V_i_1
+
+
+def hash_msg(msg):
+    # print(msg)
+    len1 = len(msg)
+    reserve1 = len1 % 64
+    msg.append(0x80)
+    reserve1 = reserve1 + 1
+    # 56-64, add 64 byte
+    range_end = 56
+    if reserve1 > range_end:
+        range_end = range_end + 64
+
+    for i in range(reserve1, range_end):
+        msg.append(0x00)
+
+    bit_length = len1 * 8
+    bit_length_str = [bit_length % 0x100]
+    for i in range(7):
+        bit_length = int(bit_length / 0x100)
+        bit_length_str.append(bit_length % 0x100)
+    for i in range(8):
+        msg.append(bit_length_str[7 - i])
+
+    # print(msg)
+
+    group_count = round(len(msg) / 64)
+
+    B = []
+    for i in range(0, group_count):
+        B.append(msg[i * 64:(i + 1) * 64])
+
+    V = [IV]
+    for i in range(0, group_count):
+        V.append(CF(V[i], B[i]))
+
+    y = V[i + 1]
+    result = ""
+    for i in y:
+        result = '%s%08x' % (result, i)
+    return result
+
+
+def str2byte(msg):  # 字符串转换成byte数组
+    ml = len(msg)
+    msg_byte = []
+    msg_bytearray = msg.encode('utf-8')
+    for i in range(ml):
+        msg_byte.append(msg_bytearray[i])
+    return msg_byte
+
+
+def byte2str(msg):  # byte数组转字符串
+    ml = len(msg)
+    str1 = b""
+    for i in range(ml):
+        str1 += b'%c' % msg[i]
+    return str1.decode('utf-8')
+
+
+def hex2byte(msg):  # 16进制字符串转换成byte数组
+    ml = len(msg)
+    if ml % 2 != 0:
+        msg = '0' + msg
+    ml = int(len(msg) / 2)
+    msg_byte = []
+    for i in range(ml):
+        msg_byte.append(int(msg[i * 2:i * 2 + 2], 16))
+    return msg_byte
+
+
+def byte2hex(msg):  # byte数组转换成16进制字符串
+    ml = len(msg)
+    hexstr = ""
+    for i in range(ml):
+        hexstr = hexstr + ('%02x' % msg[i])
+    return hexstr
+
+
+def Hash_sm3(msg, Hexstr=0):
+    if Hexstr:
+        msg_byte = hex2byte(msg)
+    else:
+        msg_byte = str2byte(msg)
+    return hash_msg(msg_byte)
+
+
+def KDF(Z, klen):  # Z为16进制表示的比特串(str),klen为密钥长度(单位byte)
+    klen = int(klen)
+    ct = 0x00000001
+    rcnt = ceil(klen / 32)
+    Zin = hex2byte(Z)
+    Ha = ""
+    for i in range(rcnt):
+        msg = Zin + hex2byte('%08x' % ct)
+        # print(msg)
+        Ha = Ha + hash_msg(msg)
+        # print(Ha)
+        ct += 1
+    return Ha[0: klen * 2]
+
+
+if __name__ == '__main__':
+    y = Hash_sm3('aee694b9e5908ee9878de590afe7949f010000003d2e8b123c2e8b1211180000be3e', 1)
+    print(y)
+
+    # klen = 19
+    # print(KDF("57E7B63623FAE5F08CDA468E872A20AFA03DED41BF1403770E040DC83AF31A67991F2B01EBF9EFD8881F0A0493000603", klen))