家庭移动环境监测和能耗监测, 433M无线数据传送乐联
本帖最后由 gpwang2000 于 2013-8-29 18:14 编辑乐联的家庭能耗活动搞得如火如荼, 利用手里现成的模块搭了一套系统,在群里得到廋网虫、小叶子、老顽童等的帮助。
移动端包括BMP085 + DSM501A + LCD5110 + 电量模块 + ArduinoNano + 433M发射,无线网关包括433M超再生接收 + ArduinoUno + ENC28J60,无线数据传输以最常见价格最低廉的433M收发模块为基础,利用VirtualWire库实现了无线数据的单向传送,一次最大可传80个字节,另外为了方便系统串口调试, 与电量模块的通信使用了软件串口。
无线网关部分程序, 主要完成数据接收并上传到乐为物联
#include <VirtualWire.h>
#include <EtherCard.h>
#define INTEGER(x) (long) x
#define DECIMAL(x) (long)(abs(x)*100L+0.5) % 100
#define DATA_COUNT 9
// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
uint8_t Ethernet::buffer;
// lewei50
//char lwSite[] PROGMEM = "192.168.1.148";
char lwSite[] PROGMEM = "www.lewei50.com";
char lwUrl[] PROGMEM = "/api/V1/gateway/UpdateSensors/01";
char lwKey[] PROGMEM = "userkey: xxxxxxxxxxxxxxxxxxxxxxxxxx";
char *lwSensor={"T", "P", "PM10", "PM25", "V", "KWH", "W", "A", "PF"};
union DATA{
float value;
struct{
float Temperature;//温度
float Pressure; //气压
float Pm10; //1um粒子
float Pm25; //2.5um粒子
float Voltage; //电压
float Kwh; //电量
float Watt; //功率
float Amp; //电流
float Pf; //功率因素
}item;
}data;
uint8_t lwSend = 0;
uint8_t lwCount = 0;
uint32_t sendTime;
// called when the client request is complete
static void my_result_cb (byte status, word off, word len) {
Serial.print("<<< reply ");
Serial.print(millis() - sendTime);
Serial.println(" ms");
Serial.println((const char*) Ethernet::buffer + off);
}
void setup() {
Serial.begin(9600);
// 初始化接收模块,速率为1200bps
vw_setup(1200);
vw_rx_start();
//初始化以太网卡
Serial.println("ethercard");
while(ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0) {
Serial.println( "Failed");
delay(2000);
}
//初始化IP地址
Serial.println("dhcp");
while (!ether.dhcpSetup()) {
Serial.println("failed");
delay(2000);
}
ether.printIp("My IP: ", ether.myip);
ether.printIp("GW IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);
//网址预处理
ether.dnsLookup(lwSite);
}
void loop() {
uint8_t buf;
uint8_t buflen = VW_MAX_MESSAGE_LEN;
char str;
ether.packetLoop(ether.packetReceive());
//无线数据接收
if (vw_get_message(buf, &buflen)) {
if (buflen != sizeof(data)){
Serial.println("recv error");
return;
}
//处理收到的数据
float *p = (float *)buf;
for (int i=0; i<DATA_COUNT; i++){
//记录传输间隔内的最大值
if (p > data.value) data.value = p;
}
lwSend = 1;
}
//数据分批发送至乐联网,每个数据约5分钟传一次
if (lwSend == 1){
sprintf(str,"[{\"Name\":\"%s\",\"Value\":\"%ld.%ld\"}]", lwSensor, INTEGER(data.value),DECIMAL((data.value)));
Serial.println(str);
ether.dnsLookup(lwSite);
ether.printIp("Server: ", ether.hisip);
sendTime = millis();
ether.httpPost (lwUrl, lwSite, lwKey, str, my_result_cb);
data.value = 0;
if (++lwCount >= DATA_COUNT) lwCount = 0;
lwSend = 0;
}
}
移动采集部分程序, 主要收集各个模块的数据从433M一并发送,约30秒发送一次
#include <Wire.h>
#include <ModbusMaster.h>
#include <Adafruit_BMP085.h>
#include <SoftwareSerial.h>
#include <VirtualWire.h>
#include <lcd5110.h>
#include <dsm501a.h>
#include <AcMeter.h>
#define INTEGER(x) (long) x
#define DECIMAL(x) (long)(abs(x)*100L+0.5) % 100
#define DATA_COUNT 9
Adafruit_BMP085 bmp;
DSM501A dsm(A2, A3);
ACMETER meter;
union{
float value;
struct{
float Temperature;//温度
float Pressure; //气压
float Pm10; //1um粒子
float Pm25; //2.5um粒子
float Voltage; //电压
float Kwh; //电量
float Watt; //功率
float Amp; //电流
float Pf; //功率因素
}item;
}data;
void setup()
{
//初始化串口
Serial.begin(9600);
// 初始化发送模块,速率为1200bps
Serial.println("vm");
vw_setup(1200);
// 初始化5110液晶模块
Serial.println("lcd5110");
LCD_init();
//初始化bmp085模块
Serial.println("bmp085");
while(!bmp.begin()){
Serial.println("Fialed!");
delay(2000);
}
// 启动粉尘检测
Serial.println("dsm start");
dsm.begin();
}
void loop()
{
uint8_t i, result;
//dsm.loop == 1, 处于粉尘采样阶段
if (dsm.loop() == 1) return;
//提取粉尘数据
data.item.Pm10 = dsm.pm10;
data.item.Pm25 = dsm.pm25;
//提取bmp085温度和气压数据
data.item.Temperature = bmp.readTemperature();
data.item.Pressure = bmp.readPressure();
//提取电量信息
if (meter.read() == 0){
data.item.Voltage = meter.Voltage;
data.item.Amp = meter.Amp;
data.item.Watt = meter.Watt;
data.item.Pf = meter.Pf;
data.item.Kwh = meter.Kwh;
}
//LCD显示数据
char str;
LCD_clear();//清屏
sprintf(str, "TIME: %ld", millis());
LCD_write_english_string(0,0,str);
sprintf(str, "PM10: %ld.%ld", INTEGER(data.item.Pm10), DECIMAL(data.item.Pm10));
LCD_write_english_string(0,1,str);
sprintf(str, "PM25: %ld.%ld", INTEGER(data.item.Pm25), DECIMAL(data.item.Pm25));
LCD_write_english_string(0,2,str);
sprintf(str, "TEMP: %ld.%ld", INTEGER(data.item.Temperature), DECIMAL(data.item.Temperature));
LCD_write_english_string(0,3,str);
sprintf(str, "PRES: %ld", INTEGER(data.item.Pressure));
LCD_write_english_string(0,4,str);
sprintf(str, "VOLT: %ld", INTEGER(data.item.Voltage), DECIMAL(data.item.Voltage));
LCD_write_english_string(0,5,str);
//数据发送至无线网关
vw_send((uint8_t *)&data, sizeof(data));
vw_wait_tx(); // Wait until the whole message is gone
//再次启动粉尘检测
Serial.println("dsm start");
dsm.begin();
}
硬件连接情况
以下是一些参考库
乐联电量:http://www.lewei50.com/event/detail/1
BMP085:https://github.com/adafruit/Adafruit-BMP085-Library
虚拟串口:http://www.arduino.cc/en/Reference/SoftwareSerial
MODBUS:http://playground.arduino.cc/Code/ModbusMaster
ViturlWire:http://www.geeetech.com/wiki/index.php/433Mhz_RF_link_kit
28J60:https://github.com/jcw/ethercard
LCD5110:http://www.geek-workshop.com/thread-713-2-1.html
DSM501A:http://www.geek-workshop.com/forum.php?mod=viewthread&tid=1747
本帖最后由 gpwang2000 于 2013-8-29 19:40 编辑
自己坐沙发,继续发图,
移动端照片, 用了个酸奶盒安装所有模块
正面
背面
屏幕显示
无线网关照片, 目前还未装箱
学习了啊,楼主很强大啊:lol 好勁呀, DIY, dsm501的库 可以发我吗 我一直没找到 楼主 数据怎么从union里取出来呐?这段看不明白! 几天没玩arduino,好东西很多啊!:lol 连线表格做得很清楚。 程序学习了,谢谢 用什么供电的呢,电池可以用多久?
页:
[1]