|
本帖最后由 x1816 于 2016-11-12 10:38 编辑
Raspberry Pi 3拥有一组GPIO接口,上面有SPI、I2C等常用的总线接口,还集成了蓝牙功能,可以比较方便地连接各种传感器件,另外其无线网络可以很轻松的连接到各大云平台。
通过本文可以搭建的系统结构图:
之前的分享一直把Raspberry Pi作为一个小服务器使用,对用户提供服务。而这篇分享会把Raspberry Pi用作一个物联网接入的网关,并利用GPIO,衔接传感器和物联网平台。
接入外部传感器
与其精挑细选,犹豫再三,不如立即行动。手边正好有个传感器模块,看看能不能接到Raspberry Pi上。
名称是BH1750数字环境光强度传感器
模块通过3.3V供电,使用I2C总线通信,连接到Raspberry Pi上的供电口和I2C接口就可以了(ADDR是地址线,这里接地)。
用i2cdetect –y 1看一下,确认已经连上:
看到那个23,说明接线都正确了,接下来就要写程序读取传感器数据了。
一种方法是读datasheet,慢慢调试。但是bh1750不是特别新的传感器,已经有热心网友写好了类库,我找了一个python版本的(bh1750.py)。
- https://gist.github.com/oskar456/95c66d564c58361ecf9f
复制代码- #!/usr/bin/python2
- # vim: expandtab ts=4 sw=4
- # Inspired by http://www.raspberrypi-spy.co.uk/2015/03/bh1750fvi-i2c-digital-light-intensity-sensor/
-
-
- import smbus
- import time
-
- class BH1750():
- """ Implement BH1750 communication. """
- # Define some constants from the datasheet
- POWER_DOWN = 0x00 # No active state
- POWER_ON = 0x01 # Power on
- RESET = 0x07 # Reset data register value
- # Start measurement at 4lx resolution. Time typically 16ms.
- CONTINUOUS_LOW_RES_MODE = 0x13
- # Start measurement at 1lx resolution. Time typically 120ms
- CONTINUOUS_HIGH_RES_MODE_1 = 0x10
- # Start measurement at 0.5lx resolution. Time typically 120ms
- CONTINUOUS_HIGH_RES_MODE_2 = 0x11
- # Start measurement at 1lx resolution. Time typically 120ms
- # Device is automatically set to Power Down after measurement.
- ONE_TIME_HIGH_RES_MODE_1 = 0x20
- # Start measurement at 0.5lx resolution. Time typically 120ms
- # Device is automatically set to Power Down after measurement.
- ONE_TIME_HIGH_RES_MODE_2 = 0x21
- # Start measurement at 1lx resolution. Time typically 120ms
- # Device is automatically set to Power Down after measurement.
- ONE_TIME_LOW_RES_MODE = 0x23
-
- def __init__(self, bus, addr=0x23):
- self.bus = bus
- self.addr = addr
- self.power_down()
- self.set_sensitivity()
-
- def _set_mode(self, mode):
- self.mode = mode
- self.bus.write_byte(self.addr, self.mode)
-
- def power_down(self):
- self._set_mode(self.POWER_DOWN)
-
- def power_on(self):
- self._set_mode(self.POWER_ON)
-
- def reset(self):
- self.power_on() #It has to be powered on before resetting
- self._set_mode(self.RESET)
-
- def cont_low_res(self):
- self._set_mode(self.CONTINUOUS_LOW_RES_MODE)
-
- def cont_high_res(self):
- self._set_mode(self.CONTINUOUS_HIGH_RES_MODE_1)
-
- def cont_high_res2(self):
- self._set_mode(self.CONTINUOUS_HIGH_RES_MODE_2)
-
- def oneshot_low_res(self):
- self._set_mode(self.ONE_TIME_LOW_RES_MODE)
-
- def oneshot_high_res(self):
- self._set_mode(self.ONE_TIME_HIGH_RES_MODE_1)
-
- def oneshot_high_res2(self):
- self._set_mode(self.ONE_TIME_HIGH_RES_MODE_2)
-
- def set_sensitivity(self, sensitivity=69):
- """ Set the sensor sensitivity.
- Valid values are 31 (lowest) to 254 (highest), default is 69.
- """
- if sensitivity < 31:
- self.mtreg = 31
- elif sensitivity > 254:
- self.mtreg = 254
- else:
- self.mtreg = sensitivity
- self.power_on()
- self._set_mode(0x40 | (self.mtreg >> 5))
- self._set_mode(0x60 | (self.mtreg & 0x1f))
- self.power_down()
-
- def get_result(self):
- """ Return current measurement result in lx. """
- data = self.bus.read_word_data(self.addr, self.mode)
- count = data >> 8 | (data&0xff)<<8
- mode2coeff = 2 if (self.mode & 0x03) == 0x01 else 1
- ratio = 1/(1.2 * (self.mtreg/69.0) * mode2coeff)
- return ratio*count
-
- def wait_for_result(self, additional=0):
- basetime = 0.018 if (self.mode & 0x03) == 0x03 else 0.128
- time.sleep(basetime * (self.mtreg/69.0) + additional)
-
- def do_measurement(self, mode, additional_delay=0):
- """
- Perform complete measurement using command
- specified by parameter mode with additional
- delay specified in parameter additional_delay.
- Return output value in Lx.
- """
- self.reset()
- self._set_mode(mode)
- self.wait_for_result(additional=additional_delay)
- return self.get_result()
-
- def measure_low_res(self, additional_delay=0):
- return self.do_measurement(self.ONE_TIME_LOW_RES_MODE, additional_delay)
-
- def measure_high_res(self, additional_delay=0):
- return self.do_measurement(self.ONE_TIME_HIGH_RES_MODE_1, additional_delay)
-
- def measure_high_res2(self, additional_delay=0):
- return self.do_measurement(self.ONE_TIME_HIGH_RES_MODE_2, additional_delay)
-
-
- def main():
-
- #bus = smbus.SMBus(0) # Rev 1 Pi uses 0
- bus = smbus.SMBus(1) # Rev 2 Pi uses 1
- sensor = BH1750(bus)
-
- while True:
- print "Sensitivity: {:d}".format(sensor.mtreg)
- for measurefunc, name in [(sensor.measure_low_res, "Low Res "),
- (sensor.measure_high_res, "HighRes "),
- (sensor.measure_high_res2, "HighRes2")]:
- print "{} Light Level : {:3.2f} lx".format(name, measurefunc())
- print "--------"
- sensor.set_sensitivity((sensor.mtreg + 10) % 255)
- time.sleep(1)
-
-
- if __name__=="__main__":
- main()
复制代码
写一个bh1750_test.py简单测试一下:
- # -*- coding: utf-8 -*-
- from bh1750 import BH1750
- import smbus
- bus = smbus.SMBus(1) # Rev 2 Pi uses 1
- bhsensor = BH1750(bus)
- bhsensor.set_sensitivity(254)
- result = bhsensor.measure_high_res()
- print int(result)
复制代码 工作正常,可以读取光照值。
另外加个CPU温度的监控吧:
Raspberry Pi的CPU温度可以通过如下代码获得:
- # -*- coding: utf-8 -*-
- # 打开文件
- file = open("/sys/class/thermal/thermal_zone0/temp")
- # 读取结果,并转换为浮点数
- temp = float(file.read()) / 1000
- # 关闭文件
- file.close()
- # 向控制台打印
- print "temp : %.1f" %temp
复制代码
本质上就是读取一个文件,结果如下(有小风扇吹着,温度不高):
接入云平台服务
接下来该推送到云端,先找个云平台注册。
我使用的是中国移动物联网开放平台OneNET:
网站上有详细的教程,说明如何接入,这里就不重复说明了。
主要流程是创建一个产品,产品下面接入设备,每个设备可以设置多个数据流。
这里创建2个数据流:
用来接收上述2个传感器的数据。
注意创建后,记下设备ID,是7位数字,还有APIkey,相当于接入密钥。
然后在Raspberry Pi上编写访问云平台的代码(文件名iot10086.py)
- # -*- coding: utf-8 -*-
- import requests
- import json
-
- #接入类:中国移动物联网开放平台http://open.iot.10086.cn/
- class Iot10086(object):
- #api-key
- apikey =''
- #apiurl只能精确到项目----设备,设备下的datastream在set_data时指定
- apiurl=''
-
- def __init__(self,apikey,apiurl):
- self.apikey = apikey
- self.apiurl = apiurl
- self.apiheaders={'api-key':apikey}
- #设置传感器
- def set_data(self,datastream,value):
- apiurl_set = self.apiurl + '?type=3' #上传用的url要加上type3
- payload={datastream:str(value)}
- r=requests.post(apiurl_set, headers=self.apiheaders, data=json.dumps(payload), timeout=30)
- return r.status_code
- #获取传感器数值(返回dict)
- def get_data(self,datastream):
- apiurl_get = self.apiurl + '?datastream_id=' + datastream
- r=requests.get(apiurl_get, headers=self.apiheaders, timeout=20)
- if r.status_code == 200:
- return json.loads(r.text)
- else:
- return r.status_code
-
复制代码
通过HTTP接入,只需要构造合适的HTTP请求就可以了。
最后编写主程序,把获取传感器数据,推送到云端等流程写好(主程序名称:main_iot10086.py):
- # -*- coding: utf-8 -*-
- from iot10086 import Iot10086
- import datetime
- from bh1750 import BH1750
- import smbus
-
- apikey ='xxxxxxxxxxxxxxxxxxxxxxxxxxxx' #这里要输入默认APIKEY,默认关联本产品所有设备
-
- apiurl='http://api.heclouds.com/devices/xxxxxxx/datapoints'#这个apiurl里的设备ID是云平台上可以查到。
-
- iot = Iot10086(apikey,apiurl)
-
- ################################################################
- #处理bh1750数据
- ################################################################
- #获取时间戳
- timestamp = datetime.datetime.now().isoformat()[0:19] #获取ISO8601格式时间,如2016-12-30T11:00:00
- print timestamp
- #获取BH1750传感器数据
- bus = smbus.SMBus(1)
- bhsensor = BH1750(bus)
- bhsensor.set_sensitivity(254)
- bh1750_result = '%.1f'%bhsensor.measure_high_res()
- print 'bh1750_result = ' + bh1750_result
- #上传到iot10086
- iot_post_status =iot.set_data('bh1750', bh1750_result)
- print iot_post_status
- #读回iot10086记录
- #iot_result = iot.get_data('bh1750')
- #print 'iot_result = ',iot_result
-
- ################################################################
- #处理CPU Temperature数据
- ################################################################
- #获取时间戳
- timestamp = datetime.datetime.now().isoformat()[0:19] #获取ISO8601格式时间,如2016-12-30T11:00:00
- print timestamp
- #获取CPU temperature 数据
- #打开文件
- file = open("/sys/class/thermal/thermal_zone0/temp")
- # 读取结果,并转换为浮点数
- cputemp_result = '%.1f'%(float(file.read()) / 1000)
- # 关闭文件
- file.close()
-
- print 'cputemp_result = ', cputemp_result
- #上传到iot10086
- iot_post_status =iot.set_data('cputemp', cputemp_result)
- print iot_post_status
复制代码
测试一下程序,如果iot_post_status返回200,就成功了,在云平台的数据查看页面上应该也能实时看到推送的数据。
定时执行
上面的程序执行一次只能推送当前时间点的一次数据,并不具备周期性执行的功能。
要定时执行这个程序,可以用Linux的计划任务cron程序。
Raspberry Pi上的cron程序默认已经开启,我们只需要编写需要执行的内容就可以了。
执行:
注意不用加sudo,我们的程序以pi用户运行就可以了。
首次运行需要选择一个编辑器打开,在末尾加上一行:
*/1 * * * * /usr/bin/python /home/pi/IOTpy/main_iot10086.py >/dev/null 2>&1
复制代码 表示每分钟运行1次,注意程序要写完整路径。最后的>/dev/null 2>&1是输出重定向,程序是后台运行,把输出丢弃。
查看结果
运行一段时间后,云平台上应该已经收到不少数据了。用云平台的应用管理功能,在线创建一个简单的应用,方便查看数据:
|
赞赏
-
1
查看全部赞赏
-
|