初试物联网之远程温湿度计

将 NAS 的信息显示在面板上只能帮助家人在房间内了解信息,但更重要的是如何能够在远程获取房间内的状态呢?为了实现将远程房间内物理信息传送到云端,需要以下的几个环节相互配合

  • 物联网数据平台,作为云端保存和处理数据
  • 传感器,采集环境信息产生数据
  • 家庭网关,将传感器信息收集传送到云平台
Internet of Things
Internet of Things

随着软银宣布收购 ARM 在物联网大展拳脚,Iot 这个不断翻炒的菜也在不断升温,国内除了百度物接入阿里云,流行的物联网数据平台中 Yeelink乐联网算是比较典型解决方案。他们都提供了通过 HTTP 访问的 RESTful API 将分布在各处的数据传送到他们的数据平台上,这种开发方式对绝大多数不会产生大量数据的小客户进行快速开发是非常方便的,下面的代码就能说明。不过周末尝试了好久,就是无法在 Yeelink 上成功的注册帐号,只好转战乐联网了,不过由于 API 基本类似,即便是转平台也是非常快捷的。如果有虚拟主机,也可以自己直接采用开源的 opensensordata.net 搭建一个云端的数据平台。

先直接把将数据传送到乐联网的 Python 网关代码罗列到这里。主要实现的功能就是读取传感器信息,然后以 JSON 格式发送到服务器。这个程序将由 cron 定时运行。

需要指出的是,乐联网的 API 中对 userkey 的请求有一个违反 HTTP 协议的地方——大小写敏感!在无数遍用 urllib2 进行调试后,发现 urllib2 会自动的将 headers 中的 “userkey” 改写为 “Userkey”,进而导致乐联网认为请求没有发送这个信息。所以在用 Python 进行开发的时候,只能采用 Request 来进行。

#!/usr/bin/env python

from os import popen
import re
import json
import requests
import serial
import time


UPDATE_SENSOR_URL='http://www.lewei50.com/api/V1/gateway/UpdateSensors/XXXXXX'
USER_KEY = 'xxxxxxxxxxxx'
SERIAL_PORT = '/dev/ttyACM0'

def get_room_temp():
    ser = serial.Serial(SERIAL_PORT, 9600)
    ser.isOpen()

    ser.write(r'read')
    ser.flush()

    #DHT11 reading need some time
    time.sleep(5)

    result = ''
    while ser.in_waiting > 0:
            result += ser.read(ser.in_waiting)

    ser.close()
    #
    # TODO: Correct message from Arduino not here
    #
    data = result[result.find('['): result.find(']') + 1]
    data = data.replace("Humidity", "room-humidity")
    data = data.replace("Temperature", "room-temp")
    #print data
    return json.loads(data)

def get_cpu_temp():
    # Get CPU temperature by lm_sensors
    nums = re.compile(r'\d+\.\d*')
    cpu_temp = []
    index = 1
    for line in popen('/usr/bin/sensors').read().split('\n'):
        if line[:4] == 'Core':
            cpu_temp.append({
                'Name': 'core%d-temp' % index,
                'Value': nums.search(line).group(0)
            })
            index = index + 1
    return cpu_temp

def main():
    cpu_data = get_cpu_temp()
    room_data = get_room_temp()
    #print room_data
    response = requests.post(UPDATE_SENSOR_URL,
            data=json.dumps(cpu_data + room_data), 
            headers={'userkey': USER_KEY})
    result = response.json()

    if result['Successful']:
        print "Successful update the sensor values"
        return 0
    else:
        print "Faild to update for %s" % result['Message']
        return -1
    

if __name__ == '__main__':
    main()

 

读取传感器信息的时候需要和传感器硬件进行配合,比如报文和时间间隔。在本案例中所采用的温度传感器为 DHT11,每次读取它都需要一定的时间,加上串口通讯的延迟,需要在程序中考虑做一点额外的延迟处理。而读取 CPU 的温度则无需等待,直接将 lm_sensors 采集的信息整理即可发送了。

总结一下,基于 HTTP 请求的数据服务进行物联网数据网管的开发是非常简单的,甚至可以采用 Linux 命令行直接上传数据到云端,不过这种灵活的数据交互方式也存在一个弊病——没有统一的请求方法标准和编码格式,对嵌入式设备来说传输字符串的负担实在有点重了。另外一种物联网数据服务传输方式则是 MQTT 协议,并得到了如百度物云,IBM 这些互联网巨头的支持,极有可能成为将来物联网通讯的基石。

回到这个起步的物联网方案中的数据采集终端。这里采用的温度传感器则是最为普通的 DHT11 加上 Arduino UNO 了。推荐这个方案是出于以下原因:

  • DHT11 (数据手册)有非常稳定的性能,价格也非常低廉,非常适宜于 DIY。同时 DHT11 能同时测量温度和湿度两个信息,却只用了 1 个数据管脚,将来如果采用 Arduino Nano 之类的开发板也不用担心 I/O 不够的问题了。同时,Arduino 上已经有 DHT 成熟库,可以直接拖过来使用。
  • Arduino UNO 的 USB 可以直接和绝大多数 Linux 系统交互,直接可以实现 USB 到串口的转换。而且直接解决供电的问题。

DHT11 和 Arduino UNO 的接线图如下,只需要连接三根线:5V,地和数据线。建议数据线用一个 5kΩ的电阻上拉到 5V,不过我测试的时候手头没有电阻,就直接连上 I/O 端子发现也能工作。DHT11典型接线图

温湿度传感器的 Arduino 源代码直接奉上,其实来很简单

  • 等待来自 PC 的命令,这里是 “read” 单词。这种方式可以有效的减少运行时间,将来可以做成中断,平时单片机甚至可以进入休眠状态来省电。
  • 然后开始读取传感器信息:温度,湿度
  • 将信息打包成 JSON 格式的字符串,通过串口送出去。如果 PC 那里只是简单的脚本也可以方便处理这些信息。
#include <DHT.h>

#define DHTPIN 7
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);
byte last_byte = 0;

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void send_data(){
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float humidity = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float temperature = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(humidity) || isnan(temperature)) {
    //Serial.println("Fail");
    //Serial.flush();
    return;
  }

  Serial.print("[{\"Name\":\"Humidity\", \"Value\":\"");
  Serial.print(humidity);
  Serial.print("\"},{\"Name\":\"Temperature\", \"Value\":\"");
  Serial.print(temperature);
  Serial.println("\"}]");
  Serial.flush();
}

void loop() {
  // Only send out data if command from PC  
  while (Serial.available()){
    int inChar = Serial.read();
    Serial.println( (char)inChar);
    if(inChar < 0){
      return;
    }
    switch(last_byte){
      case 0:
        if(inChar == 'r'){
          last_byte = (byte)inChar;
        }else{
          last_byte = 0;
        }
        break;
      case 'r':
        if(inChar == 'e'){
          last_byte = (byte)inChar;
        }else{
          last_byte = 0;
        }
        break;
      case 'e':
        if(inChar == 'a'){
          last_byte = (byte)inChar;
        }else{
          last_byte = 0;
        }
        break;
      case 'a':
        if(inChar == 'd'){
          send_data();
          delay(1000);
          last_byte = 0;
        }else{
          return;
        }
        break;
      default:
        return;
        break;
    }
  } 
}

 

在 Arduino 中实现了一个简单的报文分析和应答的功能。接下来如果还要连接更多的传感器,这个 Arduino 将是一个非常好的基础。所以这里可能还要加上更多的通讯功能。

将 Arduino 连进电脑的 USB 接口,并设置 cron 定时(我设置 10 分钟运行一次)运行网管 python 程序,一段时间后就可以在乐联上看到类似的监控数据了。

湿度数据

随着获取了信息,接下来还能让这些数据干什么呢?

  • 读取云端的数据,如果温湿度太高,发出消息或者直接控制家庭中的某些设备,特别是有宠物的家庭这个还是挺重要的。这个程序可以是一个手机 App,也可以是其他云端程序。
  • 云端的微信消息中转,将云端的数据加工整理成图片,仪表盘发给家里人。

简单总结一下:

  • 随着物联网平台的兴起,实现家庭数据通互联网已经变得非常简单,像上面一百行 Python 代码就可以将家里多个传感器信息送到远程服务器上。数据服务将是一个非常有潜力的物联网公共基础设施,只是现在的主要玩家还刚刚起步。
  • 传感器的多元伴随着像是 Arduino 这样的半成品,极大的促进了大量开发者进行快速开发的能力。
  • 数据的产生者 – 输送者都已经具备,我们等待着数据消费者一起撬动整个物联网的下一个飞跃。

 

“初试物联网之远程温湿度计”的一个回复

  1. Arduino 报文解析程序没有考虑超时处理,即收到部分报文后断线,在一定长时间内没有收到后续报文,自动恢复到没有报文的状态。

发表评论

电子邮件地址不会被公开。 必填项已用*标注