5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)

综合案例- 将温湿度数据发送到云端

  • 案例说明
  • 功能实现
    • 1、物联网平台开发
    • 2、设备端开发
    • (2)代码
    • (3)测试效果

案例说明

温湿度传感器测量当前温湿度,将实时温湿度信息上传云端,从而实现云端的监管。
传感器使用详见3.11 haas506 2.0开发教程-example-温湿度传感器(AHT10)
案例使用阿里云为例,将温湿度信息显示在阿里云。

功能实现

1、物联网平台开发

第一次使用物联网平台的读者,需要开通实例后使用物联网平台功能。也可以使用免费的公共实例进行开发,在阿里云物联网平台中,左上角选择‘华东2-上海’,点击‘公共实例’,即可开通。

1、平台产品创建可参考haas506 2.0开发教程-aliyunIoT
2、创建产品属性(添加物模型)
选择产品功能定义编辑草稿
5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第1张图片
1、添加自定义功能
2、添加标识符数据类型(标识符要与代码一致)
3、点击发布上线
5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第2张图片

5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第3张图片

物模型数据可以删除json文件,也可以上传zip压缩包
5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第4张图片

  • 物模型数据内容,将下列物模型内容保存为json或zip文件进行上传

  • model.json

{
  "schema": "https://iotx-tsl.oss-ap-southeast-1.aliyuncs.com/schema.json",
  "profile": {
    "version": "1.0",
    "productKey": "a1nz0jhv9uS"
  },
  "properties": [
    {
      "identifier": "IMEI",
      "name": "IMEI",
      "accessMode": "r",
      "required": false,
      "dataType": {
        "type": "text",
        "specs": {
          "length": "64"
        }
      }
    },
    {
      "identifier": "ICCID",
      "name": "ICCID",
      "accessMode": "r",
      "required": false,
      "dataType": {
        "type": "text",
        "specs": {
          "length": "64"
        }
      }
    },
    {
      "identifier": "temperature",
      "name": "temperature",
      "accessMode": "r",
      "required": false,
      "dataType": {
        "type": "double",
        "specs": {
          "min": "-10",
          "max": "100",
          "unit": "°C",
          "unitName": "摄氏度",
          "step": "0.00000001"
        }
      }
    },
    {
      "identifier": "humidity",
      "name": "humidity",
      "accessMode": "r",
      "required": false,
      "dataType": {
        "type": "double",
        "specs": {
          "min": "0",
          "max": "100",
          "unit": "%RH",
          "unitName": "相对湿度",
          "step": "0.0000001"
        }
      }
    }
  ],
  "events": [
    {
      "identifier": "post",
      "name": "post",
      "type": "info",
      "required": true,
      "desc": "属性上报",
      "method": "thing.event.property.post",
      "outputData": [
        {
          "identifier": "IMEI",
          "name": "IMEI",
          "dataType": {
            "type": "text",
            "specs": {
              "length": "64"
            }
          }
        },
        {
          "identifier": "ICCID",
          "name": "ICCID",
          "dataType": {
            "type": "text",
            "specs": {
              "length": "64"
            }
          }
        },
        {
          "identifier": "temperature",
          "name": "temperature",
          "dataType": {
            "type": "double",
            "specs": {
              "min": "-10",
              "max": "100",
              "unit": "°C",
              "unitName": "摄氏度",
              "step": "0.00000001"
            }
          }
        },
        {
          "identifier": "humidity",
          "name": "humidity",
          "dataType": {
            "type": "double",
            "specs": {
              "min": "0",
              "max": "100",
              "unit": "%RH",
              "unitName": "相对湿度",
              "step": "0.0000001"
            }
          }
        }
      ]
    }
  ],
  "services": [
    {
      "identifier": "set",
      "name": "set",
      "required": true,
      "callType": "async",
      "desc": "属性设置",
      "method": "thing.service.property.set",
      "inputData": [],
      "outputData": []
    },
    {
      "identifier": "get",
      "name": "get",
      "required": true,
      "callType": "async",
      "desc": "属性获取",
      "method": "thing.service.property.get",
      "inputData": [
        "IMEI",
        "ICCID",
        "temperature",
        "humidity"
      ],
      "outputData": [
        {
          "identifier": "IMEI",
          "name": "IMEI",
          "dataType": {
            "type": "text",
            "specs": {
              "length": "64"
            }
          }
        },
        {
          "identifier": "ICCID",
          "name": "ICCID",
          "dataType": {
            "type": "text",
            "specs": {
              "length": "64"
            }
          }
        },
        {
          "identifier": "temperature",
          "name": "temperature",
          "dataType": {
            "type": "double",
            "specs": {
              "min": "-10",
              "max": "100",
              "unit": "°C",
              "unitName": "摄氏度",
              "step": "0.00000001"
            }
          }
        },
        {
          "identifier": "humidity",
          "name": "humidity",
          "dataType": {
            "type": "double",
            "specs": {
              "min": "0",
              "max": "100",
              "unit": "%RH",
              "unitName": "相对湿度",
              "step": "0.0000001"
            }
          }
        }
      ]
    }
  ]
}
  • 发布上线,点击确定
    5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第5张图片

2、设备端开发

  • 第一次使用开发板的读者可以按照haas5062.0开发教程-导学篇搭建开发环境。
  • 搭建完后复制以下代码到Visual Studio Code,复制产品证书到代码相应位置。
    5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第6张图片

(2)代码

(4)将设备的productKey和productSecret复制到main.py代码中的相应位置

  • 2.2版本获取IMEI号接口有更新,需要更改以下内容(Ctrl+F 查找modem)
# 获取设备的IMEI 作为deviceName 进行动态注册
deviceName = modem.info.getDevImei()
...

  • main.py
# coding=utf-8

from driver import GPIO
import network
import ujson
import utime as time
import modem
from  aliyunIoT import Device
import ota
import kv
from ahtx0 import AHT10


 # ota 消息推送的接受函数
def on_trigger(data):
     global info
 # 保存服务端推送的ota信息
     info['url'] = data['url']
     info['length'] = data['length']
     info['module_name'] = data['module_name']
     info['version'] = data['version']
     info['hash'] = data['hash']
     info['hash_type'] = data['hash_type']
    # 开始ota 包下载
     dl_data = {}
     dl_data['url'] = info['url']
     dl_data['store_path'] = info['store_path']
     ota.download(dl_data)



 # ota 升级包下载结果回调函数
def on_download(data):
     global info
     if data >= 0:
         print('Ota download succeed')
     # 开始ota包校验
         param = {}
         param['length'] = info['length']
         param['store_path'] = info['store_path']
         param['hash_type'] = info['hash_type']
         param['hash'] = info['hash']
         ota.verify(param)

 # ota 升级包校验结果回调函数
def on_verify(data):
      global info
      print(data)
      if data >= 0 :
          print('Ota verify succeed')
          print('Start Upgrade')
     # 开始ota升级
          param = {}
          param['length'] = info['length']
          param['store_path'] = info['store_path']
          param['install_path'] = info['install_path']
          ota.upgrade(param)

 # ota 升级包结果回调函数
def on_upgrade(data):
     if data >= 0 :
        print('Ota succeed')
        #ota升完级后 重启设备
        reboot()
 
#当iot设备连接到物联网平台的时候触发'connect' 事件
def on_connect(data):
    global module_name,default_ver,productKey,deviceName,deviceSecret,on_trigger,on_download,on_verify,on_upgrade
    print('***** connect lp succeed****')
    data_handle = {}
    data_handle['device_handle'] = device.getDeviceHandle()

 # 初始化ota服务
    ota.init(data_handle)

 # ota 回调函数注册
    ota.on(1,on_trigger)
    ota.on(2,on_download)
    ota.on(3,on_verify)
    ota.on(4,on_upgrade)
    report_info = {
         "device_handle": data_handle['device_handle'],
         "product_key": productKey ,
         "device_name": deviceName ,
         "module_name": module_name ,
         "version": default_ver
         }
 # 上报本机ota相关信息,上报版本信息返回以后程序返回,知道后台推送ota升级包,才会调用on_trigger函数
    ota.report(report_info)    


#当连接断开时,触发'disconnect'事件
def on_disconnect():
    print('linkkit is disconnected')

#当iot云端下发属性设置时,触发'props'事件
def on_props(request):
    print('clound req data is {}'.format(request))

#当iot云端调用设备service时,触发'service'事件
def on_service(id,request):
    print('clound req id  is {} , req is {}'.format(id,request))
#当设备跟iot平台通信过程中遇到错误时,触发'error'事件
def on_error(err):
    print('err msg is {} '.format(err))

#网络连接的回调函数
def on_4g_cb(args):
     global g_connect_status
     pdp = args[0]
     netwk_sta = args[1]
     if netwk_sta == 1:
         g_connect_status = True
     else:
         g_connect_status = False

#网络连接
def connect_network():
     global net,on_4g_cb,g_connect_status
     #NetWorkClient该类是一个单例类,实现网络管理相关的功能,包括初始化,联网,状态信息等.
     net = network.NetWorkClient()
     g_register_network = False
     if net._stagecode is not None and net._stagecode == 3 and net._subcode == 1:
         g_register_network = True
     else:
         g_register_network = False
     if g_register_network:
    #注册网络连接的回调函数on(self,id,func);  1代表连接,func 回调函数  ;return 0 成功
         net.on(1,on_4g_cb)    
         net.connect(None)
     else:
         print('网络注册失败')
     while True:
         if g_connect_status:
             print('网络连接成功')
             break
         time.sleep_ms(20)

#动态注册回调函数
def on_dynreg_cb(data):
     global deviceSecret,device_dyn_resigter_succed
     deviceSecret = data
     device_dyn_resigter_succed = True


 # 连接物联网平台
def dyn_register_device(productKey,productSecret,deviceName):
    global on_dynreg_cb,device,deviceSecret,device_dyn_resigter_succed
    key = '_amp_customer_devicesecret'
    deviceSecretdict = kv.get(key)
    print("deviceSecretdict:",deviceSecretdict)
    if isinstance(deviceSecretdict,str):    
        deviceSecret = deviceSecretdict 

    if deviceSecretdict is None or deviceSecret is None:
        key_info = {
            'productKey': productKey  ,
            'productSecret': productSecret ,
            'deviceName': deviceName
            }
        # 动态注册一个设备,获取设备的deviceSecret
        #下面的if防止多次注册,当前若是注册过一次了,重启设备再次注册就会卡住,
        if not device_dyn_resigter_succed:
            device.register(key_info,on_dynreg_cb)   



if __name__ == '__main__':
    ICCID=None
    g_connect_status = False
    net = None
    device = None
    deviceSecret = None
    deviceName = None
    productKey = "a1aNr1wef2c"
    productSecret = "Jppqfgx4tHeZh1Zi"
    device_dyn_resigter_succed = False
    # 定义需要升级的模块和版本号
    module_name = 'default'
    default_ver = '1.0.0'
# 定义升级包的下载和安装路径,其中url,hash_type和hash 会通过服务端推送被保存下来

    info = {
        'url': '',
        'store_path': '/data/pyamp/app.zip',
        'install_path': '/data/pyamp/',
        'length': 0,
        'hash_type': '',
        'hash': ''
    }

    # 连接网络
    connect_network()
    # 获取设备的IMEI 作为deviceName 进行动态注册
    #2.2版本改为
    #deviceName = modem.info.getDevImei()
    deviceName = modem.getDevImei()
    #获取设备的ICCID
    ICCID=modem.sim.getIccid()
    #初始化物联网平台Device类,获取device实例
    device = Device()
    if deviceName is not None and len(deviceName) > 0 :
     #动态注册一个设备
        dyn_register_device(productKey,productSecret,deviceName)
    else:
        print("获取设备IMEI失败,无法进行动态注册")
    while deviceSecret is None:
        time.sleep(0.2)
    print('动态注册成功:' + deviceSecret)

    key_info = {
        'region' : 'cn-shanghai' ,
        'productKey': productKey ,
        'deviceName': deviceName ,
        'deviceSecret': deviceSecret ,
        'keepaliveSec': 60,
        }
    #打印设备信息
    print(key_info)

    #device.ON_CONNECT 是事件,on_connect是事件处理函数/回调函数
    device.on(device.ON_CONNECT,on_connect)
    device.on(device.ON_DISCONNECT,on_disconnect)
    device.on(device.ON_PROPS,on_props)
    device.on(device.ON_SERVICE,on_service)
    device.on(device.ON_ERROR,on_error)
    device.connect(key_info)


    #将ICCID,IMEI数据放入字典
    imei_iccid={}
    imei_iccid["IMEI"]=deviceName
    imei_iccid["ICCID"]=modem.sim.getIccid()
    #将字典转换为字符串
    imei_iccid_str=ujson.dumps(imei_iccid)
    data1={
        'params':imei_iccid_str
    }
    #10S上报一次
    time.sleep_ms(1000)
    device.postProps(data1)


    #上传温湿度信息
    a=AHT10()
    #set mode(℃ or F)
    a.set_mode(0)
    tem_hum={}
    while True:
        time.sleep(1)
        #get datas of temperature and humidity
        tem,hum=a.get_data()
        print("temperature:{},humidity:{}".format(tem,hum))
        tem_hum["temperature"]=tem
        tem_hum["humidity"]=hum
        tem_hum_str=ujson.dumps(tem_hum)
        data={
            'params':tem_hum_str
        }
        device.postProps(data)
        print('--------------------------------------------------------------------')

  • board.json
{
  "name": "haas506",
  "version": "2.0.0",
  "io": {
    "ADC0": {
      "type": "ADC",
      "port": 0,
      "sampling": 12000000
    },
    "ADC1": {
      "type": "ADC",
      "port": 1,
      "sampling": 12000000
    },
    "OLED": {
      "type": "I2C",
      "port": 1,
      "addrWidth": 7,
      "freq": 400000,
      "mode": "master",
      "devAddr": 60
    },
    "aht10": {
      "type": "I2C",
      "port": 1,
      "addrWidth": 7,
      "freq": 400000,
      "mode": "master",
      "devAddr": 56
    },      
    
    "KEY1": {
      "type": "GPIO",
      "port": 44,
      "dir": "irq",
      "pull": "pullup",
      "intMode": "rising"
    },      
    "led1": {
      "type": "GPIO",
      "port": 7,
      "dir": "output",
      "pull": "pulldown"
    },
    "led_g": {
      "type": "GPIO",
      "port": 32,
      "dir": "output",
      "pull": "pulldown"
    },            
    "SPI0": {
      "type": "SPI",
      "port": 0,
      "mode": "master",
      "freq": 2000000
    },
    "serial1": {
      "type": "UART",
      "port": 0,
      "dataWidth": 8,
      "baudRate": 115200,
      "stopBits": 1,
      "flowControl": "disable",
      "parity": "none",
      "timeout": 1000
    },
    "serial2": {
      "type": "UART",
      "port": 1,
      "dataWidth": 8,
      "baudRate": 9600,
      "stopBits": 1,
      "flowControl": "disable",
      "parity": "none",
      "timeout": 1000
    },
    "serial3": {
      "type": "UART",
      "port": 2,
      "dataWidth": 8,
      "baudRate": 115200,
      "stopBits": 1,
      "flowControl": "disable",
      "parity": "none",
      "timeout": 1000
    }
  },
  "debugLevel": "ERROR",
  "repl": "enable",
  "replPort": 0
}

  • ahtx0.py
import utime as time
from driver import I2C

#CONSTANTS
AHT10_ADDRESS = 0x38     # 0111000 (7bit address)
AHT10_READ_DELAY_MS = 75 # Time it takes for AHT to collect data
AHT_TEMPERATURE_CONST = 200
AHT_TEMPERATURE_OFFSET = 50
KILOBYTE_CONST = 1048576
CMD_INITIALIZE = bytearray([0xE1, 0x08, 0x00])
CMD_MEASURE = bytearray([0xAC, 0x33, 0x00])
FARENHEIT_MULTIPLIER = 9/5
FARENHEIT_OFFSET = 32

class AHT10:
    def __init__(self,  mode=0, address=AHT10_ADDRESS):
        self.i2c = I2C()
        self.i2c.open('aht10')

        self.address = address
        writeBuf=bytearray(4)
        writeBuf[0]=self.address
        writeBuf[1]=CMD_INITIALIZE[0]
        writeBuf[2]=CMD_INITIALIZE[1]
        writeBuf[3]=CMD_INITIALIZE[2]
        self.i2c.write(writeBuf,4)

        self.readings_raw = bytearray(8)
        self.results_parsed = [0, 0]
        self.mode = mode      # 0 for Celsius(摄氏度), 1 for Farenheit(华氏度)

    def read_raw(self):
        writeBuf=bytearray(4)
        writeBuf[0]=self.address
        writeBuf[1]=CMD_MEASURE[0]
        writeBuf[2]=CMD_MEASURE[1]
        writeBuf[3]=CMD_MEASURE[2]
        self.i2c.write(writeBuf,4)

        time.sleep_ms(AHT10_READ_DELAY_MS)
        readBuf=bytearray(6)
        readBuf[0]=AHT10_ADDRESS
        self.i2c.read(readBuf,6)
        self.readings_raw[0]=readBuf[0]
        self.readings_raw[1]=readBuf[1]
        self.readings_raw[2]=readBuf[2]
        self.readings_raw[3]=readBuf[3]
        self.readings_raw[4]=readBuf[4]
        self.readings_raw[5]=readBuf[5]

        self.results_parsed[0] = self.readings_raw[1] << 12 | self.readings_raw[2] << 4 | self.readings_raw[3] >> 4
        self.results_parsed[1] = (self.readings_raw[3] & 0x0F) << 16 | self.readings_raw[4] << 8 | self.readings_raw[5]

    def humidity(self):
        self.read_raw()
        return (self.results_parsed[0] / KILOBYTE_CONST) * 100 

    def temperature(self):
        self.read_raw()
        if self.mode is 0:
            return (self.results_parsed[1] / KILOBYTE_CONST) * AHT_TEMPERATURE_CONST - AHT_TEMPERATURE_OFFSET
        else:
            return ((self.results_parsed[1] / KILOBYTE_CONST) * AHT_TEMPERATURE_CONST - AHT_TEMPERATURE_OFFSET) * FARENHEIT_MULTIPLIER + FARENHEIT_OFFSET

    def set_mode(self, mode):
        if mode==0 or mode==1:
            self.mode = mode
        else:    
            raise ValueError('Mode must be either 0 for Celsius or 1 Farenheit')
    def get_data(self):
        # print("Temperature: " + str(self.temperature()) + ("C","F")[self.mode] + ", Humidity: " + str(self.humidity()))
        # return str(self.temperature),str(self.humidity())
        return self.temperature(),self.humidity()

(3)测试效果

(5)烧录程序,查看是否激活成功
(6)设备物模型数据传入
5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第7张图片
(7)日志输出
5.1 综合案例- 将温湿度数据发送到云端(2.2版本接口有更新)_第8张图片

你可能感兴趣的:(Haas506-2.0综合案例,嵌入式硬件,python,haas506,2.0,物联网)