Arduino上的气象站,从A到Z。第5部分

结局。 上一部分


目录:



舷外传感器。 软体类


讨论用于海外传感器的软件。 之后,您将获得一个已经可以尝试的完整系统。


让我提醒您, 服务器是可以通过WiFi与Internet进行通信的中央家用设备,而客户端是可以通过无线方式将数据传输到服务器的现成的远程传感器。


服务器和客户端的源代码都在这里
源文本提供了详细的注释。


客户端几乎不需要配置任何内容。


nRF24L01 +无线电发送器,更确切地说是RadioHead库,需要指定服务器和客户端地址。 如果您有多个服务器和客户端,则提供地址。 地址就是任何整数。 当客户端将数据包发送到服务器时,它指示该数据包用于哪个服务器。 然后,服务器知道自己的地址,然后确定此数据包是否打算发送给它。


因此,服务器和客户端上的SERVER_ADDRESS应该相同,但是不同客户端的CLIENT_ADDRESS应该不同。 换句话说,如果将来您将另一个新传感器连接到我们的系统,则需要更改CLIENT_ADDRESS


 //     #define SERVER_ADDRESS 10 #define CLIENT_ADDRESS 20 //     !!! 

每个人的RF_CHANNEL无线电频道RF_CHANNEL必须相同。 默认为2。我更改了默认数字,您可以选择其他任何数字。


 //  .       #define RF_CHANNEL 73 

必须更改用于测量电池电源电压的电压表设置:


 //   ,   const float r1 = 100400; // 100K const float r2 = 9960; // 10K //      //    http://localhost/arduino-secret-true-voltmeter/ const float typVbg = 1.082; //    1.0 -- 1.2  

为了节省能源, 使用了Arduino轻量级低功耗库


这是我使用此库的Arduino Pro Mini的实际功耗测量:


  • 通常为25mA
  • 与DHT一起使用时
  • 无线电传输38 mA
  • 在低功耗时空闲15 mA
  • 低功耗时7.5 mA

客户端对温度,湿度和电源电压进行测量,将所有这些数据打包到一个数据结构中,然后将数据发送到服务器,然后“入睡”。 如果在传输过程中发生错误,将立即重复传输。


服务器(中央,家庭单元)依次接收数据,确认接收并进行处理。


数据库,MySQL,PHP,WWW服务器


完成工作后,我们对气象站进行了功能齐全的设计。 但是现在有十角钱的这种气象站,当地的手工艺品不再流行。 毕竟,我们拥有物联网。


因此,我们将讨论如何访问您的Internet,并将数据库和Web面附加到数据库和气象站。


“网络摄像头”的问题说明:


  • 接收和存储气象站数据:温度,湿度,大气压力,电源电压
  • 显示此数据
  • 建立图表。

在这种情况下,我们需要使用mysqli模块托管对Apache,PHP和MySQL的支持。 这些条件几乎可以通过地球上的任何宿主来满足。 或代替托管,您的计算机将扮演连接到家庭网络路由器并可以访问Internet的服务器的角色。


数据库创建


让我们从头开始,即从数据库的设计和创建开始。


数据库是您的世界,您可以对其进行长期研究,因此,我们仅简要介绍一下我们直接需要的内容。


所有的SQL脚本都在weather-station/server/php-sql/目录中


数据库设计从哪里开始? 具有逻辑和物理表示。


逻辑视图或数据库模式:


  • DHT温湿度表
  • 压力和温度传感器BMP数据表
  • 指示的表之间没有任何关系,更确切地说,不需要链接。

物理方案依赖于特定的DBMS和数据类型。 使用特定示例更容易拆卸。 make_tables.sql SQL脚本make_tables.sql了逻辑和物理模式。


每个表应具有一个类型字段


 id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT 

字段名称在不同的数据库中可能有所不同,但是只有一种含义-这是唯一的标识符,即记录键。 将来,如果您在没有此类计数器的表中看到一个数据库,则应该知道该数据库是由与编程无关的人(很可能是人文科学)设计的。


我们将来自同一类型的传感器的数据存储在一个表中;对于另一类型的传感器,我们创建另一个表。 这会使数据库和与其绑定的PHP稍微复杂化,但将来会简化整个系统的扩展或修改。


我们的项目中有两个表。 arduino_dht表存储来自DHT类型的传感器(温度,湿度)的数据, arduino_bmp表存储来自BMP类型的传感器(温度,压力)的数据。 如果将来您想拥有例如气体传感器或运动检测器,那么可以创建其他表,不要偷懒。 如果连接了DHT11或DHT22类型的另一个传感器,则不需要创建其他表,请使用arduino_dht表。 我希望原则很明确:一个单独的物理实体是一个单独的表。


如果将来自多个相同类型传感器的数据存储在一个表中,那么如何区分它们呢? 为此,请在每个表中输入一个字段


 idSensor INTEGER 

实际上,这是CLIENT_ADDRESS ,我们在远程客户端-客户端的每个实例的client/client.ino中以及在server/server.ino client/client.ino为直接连接到服务器(中央单元)的传感器注册了CLIENT_ADDRESS


在工业系统中,应该有另一个表idSensor及其对应的口头,人类可读描述的对应关系。 例如, idSensor = 2的传感器是“温度,公寓内的湿度”等。 但是在我们的项目中,我们不会复杂化,只是记住:


  • 带有idSensor的传感器,它是CLIENT_ADDRESS ,等于11-这是服务器上的家庭传感器-中央单元,
  • 带有idSensor的传感器,它也是CLIENT_ADDRESS ,等于20-这是第一个(在我们的项目中,也是唯一的)基于窗口的传感器客户端。

下一个 这些表存储以下数据:


  • ipRemote-数据来自的气象站(服务器)的IP地址,对于调试和监控非常有用,
  • dateCreate-创建记录的日期,
  • millis-对调试很有用,这是自Arduino上的草图开始以来的时间(以毫秒为单位),
  • 温度-温度
  • 湿度-湿度
  • 电压-电源电压
  • 压力-压力
  • errors-错误数(未使用)。 它旨在存储传输错误等的数量,以便您可以远程评估整个系统的状态。

如您所见, arduino_dhtarduino_bmp非常相似,区别仅在于压力和湿度字段,并且希望将所有内容转储到一个堆(表)中。 但是第一个普通形式并不能命令执行此操作,许多新手程序员试图解决这个问题,但是没有一个成功,而我们不会。 这是为什么暂时不注意万有引力定律的事实。


arduino_error_log表对于调试很有用-它是错误和其他系统消息的日志。


make_db.sql描述了创建数据库及其具有权限的用户


 -- .  config.php --   CREATE DATABASE IF NOT EXISTS db_weather; --   CREATE USER 'u_weather'@'localhost' IDENTIFIED BY '***PASSWORD***'; GRANT ALL ON db_weather.* TO 'u_weather'@'localhost'; 

只需完成一次,数据库名称和用户名就可以自己输入。 真正需要做的是设置密码。


PHP和Web服务器


所有Web界面设置都存储在config.php 。 根据您的数据库设置对其进行修改。


将时区设置为PHP格式


 date_default_timezone_set('Europe/Prague'); 

此处描述了所有可用时区


设置访问密钥(以数字形式),该密钥必须与草图SOURCE_KEY中的常量SOURCE_KEY相匹配。


 $access_key = '***KEY***'; 

在我们的Web服务器中,没有授权,密码输入,这会使整个设计复杂化。 对于原型,这不是必需的。 因此,所有保护都建立在robots.txt文件上,缺少index.php和此访问密钥。


PHP的主要脚本weather.php接受带有数据的简单HTTP GET请求并将其存储在相应的数据库表中。 如果密钥$access_key不匹配,则该请求将被拒绝。


weather-view.php用于查看数据表,并包含指向其他Web界面脚本的超链接。 这样叫他


 http:// / /weather-view.php?k= access_key 

举个例子


 http://yourhost/iot/weather-view.php?k=12345 

weather-view.php显示简单的标签,您需要记住以下weather-view.php


  • ID为11的传感器是服务器上的家庭传感器,
  • ID为20的传感器是窗户传感器。

function.php脚本包含所有PHP脚本共有的功能。


chart-dht.php负责使用Google Charts进行图表绘制。 这里,例如是海外传感器的电源电压的曲线图。 在阳光灿烂的日子,由于太阳能电池,电压升高,然后电池上的电源逐渐放电。


图表


export-dht.php将数据从MySQL数据库表导出到CSV文件。 用于在电子表格中进一步导入和分析。


export-voltage.php将来自窗口传感器的电源电压数据从MySQL数据库导出到CSV文件。 对于调试很有用。


truncate.php清除所有表,即 删除我们所有的数据。 对于调试很有用。 从weather-view.php没有此脚本的链接,因此您需要使用$access_key浏览器地址栏中的直接链接来调用它。


接收数据时,通常使用mysqli_real_escape_string()函数来防止错误的值进入数据库。


不要忘记将robots.txt放在您网站的根目录,以防止它进入搜索引擎。


ESP8266,WiFi和数据传输


现在回到server.ino草图,再回到连接WiFi接入点并将数据发送到Web服务器的部分。


正如我已经写的,我找不到用于使用AT命令控制ESP8266模块的Arduino常规库,我不得不自己“集体农场”。 让我还提醒您,您必须在ESP8266-01中刷新特定版本的固件。 现在,当一切准备就绪时,让我们看看它是如何工作的。


要在server.ino草图中访问Web服务器, server.ino需要更改这些常量


 const String DEST_HOST = " "; //  habr.com const String DEST_PORT = " "; //  80 const String DEST_URL = "/ /weather.php"; const String SOURCE_KEY= "  "; //    $access_key  config.php 

server.inovoid setup()函数中,ESP8266首先切换到Station模式,即 它开始作为WiFi客户端工作


 espSendCmd(«AT+CWMODE_CUR=1», «OK», 3000); 

然后跟随连接到接入点


 espState = espConnectToWiFi(); 

如果未发生连接,则重复尝试一次


 if ( espState != ESP_SUCCESS ) { delay(5000); Serial.println("WiFi not connected! Try again ..."); espConnectToWiFi(); } 

然后选择TCP / IP单连接模式


 espSendCmd("AT+CIPMUX=0", "OK", 2000); 

将数据从DHT类型的传感器发送到Web服务器时,使用一个函数将数据type=dht指示为type=dht


 espSendData( "type=dht&t=" + String(dhtData.temperature) + "&h=" + String(dhtData.humidity) + "&v=" + String(dhtData.voltage) + "&s=" + String(CLIENT_ADDRESS) ); 

从BMP传感器向Web服务器发送数据时,使用相同的功能,数据类型表示为type=bmp


 espSendData( "type=bmp&t=" + String(temperature_bmp) + "&p=" + String(pressure_bmp) + "&s=" + String(CLIENT_ADDRESS) ); 

espSendData()函数接受HTTP GET请求字符串,并按预期将其发送到Web服务器。


在其内部, espSendData()通过向其发送“ AT”命令来检查ESP模块的可用性,然后检查WiFi连接并在必要时重新连接。 然后发送数据并关闭TCP连接。


Android应用


如今,当每个人都可以使LED闪烁时,拥有气象站的任何人都不会感到惊讶。 但是,如果工艺师知道如何通过WiFi与服务器通信,具有Web界面和移动应用程序,那么就可以了! 这里的服务器我们当然是指应用程序服务器,即 在我们的例子中,这是一个PHP绑定和一个MySQL DBMS。 蛋糕上没有足够的樱桃,即我们现在要编写的Android应用程序。


建筑学


整个气象站软件平台的架构很简单:


  • 气象站的服务器部分(中央单元)从远程传感器客户端收集数据
  • 然后将数据传输到应用程序的Web服务器,该服务器将这些数据保存到数据库
  • Android应用程序(或任何其他远程应用程序:iOS,浏览器)从Web服务器请求数据并将其显示在屏幕上。

在Android设备屏幕上,我们将显示当前的最新传感器读数。


HTTP GET和JSON


首先需要解决的问题是如何将数据从Web服务器传输到Android应用程序。


这里不需要发明任何东西,所有东西都已经为我们发明了-这些是HTTP GET和JSON。


在我们的情况下,可以在Android应用尚未准备就绪时手动编译和调试对Web服务器的简单GET请求。


在Java和Android中,有现成的库用于处理JSON格式的数据。 JSON是一种人类可读的文本格式,对于调试非常有用。


为了从气象站传感器生成当前数据, 在Web服务器上创建一个新的PHP脚本last-data-to-json.php


脚本调用:


 http://<>/last-data-to-json.php?k=<access_key> 

我们记得,其中<access_key>是秘密数据库访问密钥。


JSON格式的示例响应:


 { "DHT 11":{ "idSensor":"11", "dateCreate":"2016-04-20 18:06:03", "temperature":"19", "humidity":"26", "voltage":"5.01" }, "DHT 20":{ "idSensor":"20", "dateCreate":"2016-04-18 07:36:26", "temperature":"10", "humidity":"26", "voltage":"3.7" }, "BMP 11":{ "idSensor":"11", "dateCreate":"2016-04-20 18:06:22", "temperature":"19", "pressure":"987.97" } } 

必须记住,我们有3个传感器。 它们的ID和类型(DHT或BMP)在整个气象站代码中都进行了硬编码。 这种硬核编码方法在思想上是不正确的,但是对于膝上绘制的原型(需要快速简便的解决方案),这是一个合理的折衷方案。


 $idSensor = 11; //  DHT  $idSensor = 11; //  BMP  $idSensor = 20; //  DHT  

last-data-to-json.php从数据库中获取来自这些异构传感器的最新数据,并将其打包为JSON格式。 以这种方式从数据库“从头开始”选择数据:


 SELECT <> FROM <> ORDER BY id DESC LIMIT 1; 

安卓系统


现在,我们将编写一个简单的Android应用程序,该应用程序可以请求,接收,解码JSON数据并在屏幕上显示信息。


我们的Android应用程序将尽可能简单,这只是技术的精髓。 围绕这个“骨骼”,将已经有可能结束各种“美丽”。


这是应该导致的结果的屏幕截图


安卓系统


如您所见,UI只是基于LinearLayout的Spartan,仅此而已。


在TextView的顶部显示传感器的ID及其气象数据。 刷新按钮向Web服务器发起第二个请求。 EditText中的Next是唯一的程序设置-这是表单中的请求URL


 http://< >/last-data-to-json.php?k=<access_key> 

应该注意什么?


在清单中,添加允许Internet并检查网络连接状态的行:


 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> 

使用网络并从网站接收数据的方法如下。


我们使用AsyncTask来创建一个与主UI线程分开的后台任务。 此后台任务获取请求URL并使用它创建HttpURLConnection


建立连接后,AsyncTask将网页的内容作为InputStream加载。 接下来,将InputStream转换为字符串,然后使用JSONObject对其进行解码,并使用onPostExecute()方法将其显示在用户界面中。


在MainActivity.java中,将URL更改为:


 private static final String defUrl = "http://host/dir/last-data-to-json.php?k=< >"; 

默认情况下,它将在您首次运行Android应用程序时使用。


结语


好吧,有些事情已经奏效了。 然后,您可以优化某些内容,替换某些内容,丢弃所有内容,也可以借用某些内容。


一个单独的大痛点是能耗 。 我建议您阅读有很多实用技巧的帖子的评论。


达到无限……甚至超越。

Source: https://habr.com/ru/post/zh-CN426019/


All Articles