最近刚刚找完工作,总想鼓捣些小玩意,想到了自己有台坏掉的台灯,于是就用ESP8266对台灯进行了物联网改造,实现了通过局域网控制台灯的功能。
由于这套改造方案可以套用在除了台灯之外的其他家居设备上,因此我就大言不惭地将这套方案称为:家居设备物联网改造的解决方案。
整个方案分为三个部分:
下面针对不同部分进行介绍。
台灯里面有一张电路板负责控制,如图所示:
电路板上有四个微动按钮,从左到右分别对应了 亮度调高、色温、开关、亮度调低 这四个操作。
这些微动按钮的一侧引脚连接电源负极,另一侧按钮连接板上的控制芯片,按下按钮后控制芯片引脚检测到低电平,就会执行相应的操作。
因此,只需要向控制芯片的对应引脚发送低电平脉冲就可以模拟出点击微动按钮的效果。而发送脉冲对于ESP8266来说十分简单,具体的接线方案就不再赘述了。
IOT设备固件是整个解决方案的重中之重,由于本方案是通过局域网实现设备的控制,因此IOT设备既是用户请求的接收者,又是控制信号的发送者。除此之外,考虑到用户在第一次使用时需要对IOT设备的参数进行配置,因此还需要在固件中暴露IOT设备的配置接口。
下面我将以 配置接口->配置数据持久化->请求的接收与响应 的顺序介绍IOT设备固件。
ESP8266可以通过简单的几行代码实现http服务器的功能,这为我们暴露配置接口提供了便利。结合该单片机的WiFi热点、WiFi连接、EEPROM数据持久化功能,可以设计一套逻辑来实现设备的初始化配置。流程如下:
经过上述一套流程,IOT设备已经可以成功连接目标WiFi并开始接收控制信号和执行操作,用户可以在同一局域网中,通过客户端app扫描并连接设备,对设备发起控制。由于配置信息保存在设备的EEPROM中,因此就算设备重启,也不需要重新进行配置,除非需要切换WiFi环境。
下面对上述流程中的几个重点问题进行介绍
(1). 配置信息包含哪些?
- 设备名称
- WiFi的SSID
- WiFi的密码
(2). 如何发送配置信息?
- 还是依靠http服务器,在用户访问服务器首页时,返回一个html页面,用户通过html页面填写配置信息,并将配置信息作为表单提交给服务器;
- 当然,在服务器中需要设置表单接收和处理的相关逻辑。
- 配置界面中还添加了对于控制接口的测试按钮,如图所示:
(3). 客户端app如何扫描设备?
- 通过访问自身所处的网段和相邻网段中所有可能主机的指定路径(/identity/
),通过响应来判断该主机是否就是我们要找的设备;
- 若在访问某主机的指定路径时,得到了带有指定前缀(remote-controller
)的响应,则就可认定该主机是我们要找的设备。
(4). 数据如何在EEPROM中存储?
- 针对EEPROM的读写问题,官方提供了对应的头文件,只需要调用头文件中的函数就可以实现字节数据的存储和读取;
- 由于配置信息全都是由字符串组成,因此可以将字符串以字节的形式进行存储和读取。这样就可以实现配置信息的持久化,具体细节将在下一部分详细介绍。
void initNetwork(int timeout){// 处理wifi, getSign()是读取本地配置标记的函数if (getSign() == "Y"){String ssid = getSsid();String passwd = getPasswd();// 尝试连接wifiif (connectWifi(timeout, ssid.c_str(), passwd.c_str()))return;}// 连接wifi失败,开启ap服务startAp();
}
// 声明服务器
ESP8266WebServer server(80);
// 设置服务器对应路径的handler
void setupServer(){("/",handleIndex);("/identity/",handleIdentity); // ("/switch/", handleSwitch);// save ("/saveinfo/", handleSave);// ("/power/", handlePower);// handle ("/mode/", handleMode);// handle ("/up/", handleLightUp);// handle ("/down/", handleLightDown);NotFound(handleNotFound);server.begin();Serial.println("");
}
// 服务器中用于处理配置信息的handler
void handleSave(){if (!handlePost())return;// 解析参数const char* ssid = server.arg("ssid").c_str();const char* passwd = server.arg("passwd").c_str();Serial.printf("Receive data: nssid: %st password: %snn",ssid,passwd);// 存储wifi信息server.send(200, "text/plain", "update success, device will reboot in ");saveWifiInfoAndReset(ssid,passwd);
}// 保存配置信息并重启
void saveWifiInfoAndReset(const char* ssid, const char* passwd){// 清空数据Serial.printf("Writing data: %s, %sn", ssid, passwd);// 写入新数据saveSsid(ssid);savePasswd(passwd);saveSign();delay(5000);// 重启Serial.println("");start();
}
ESP8266上有4KB大小的EEPROM,因此可以将配置信息写入EEPROM来实现配置数据的持久化。
但是要注意的是,官方头文件只提供了字节读写操作的函数,因此在数据读写时,需要自行进行序列化和反序列化。
这一部分话不多说,直接展示写入和读取的关键代码。
// 初始化EEPROM
void initEeprom(){EEPROM.begin(128);
}/*
@Time : 2022/11/13 20:45:07
@Author : victor2022
@Desc : 写入字符串
*/
bool set_string(int addr, int size, String str)
{// 保证长度不超过最大限制size = size<str.length()?size:str.length();EEPROM.write(addr, size); // EEPROM第addr位,写入str字符串的长度//通过一个for循环,把str所有数据,逐个保存在EEPROMfor (int i = 0; i < size; i++){EEPROM.write(addr + i +1, char(str[i]));EEPROMmit();}Serial.println("Data has been saved to EEPROM!");return true; //执行保存EEPROM
}/*
@Time : 2022/11/13 20:45:24
@Author : victor2022
@Desc : 读取字符串
*/
String get_string(int addr, int size)
{// 读取长度byte tempSize = ad(addr);if(tempSize>0){size = tempSize;}addr++;// 读取数据String data = "";//通过一个for循环,从EEPROM中逐个取出每一位的值,并连接起来for (int i = 0; i < size; i++){data += ad(addr + i));}return data;
}/*
@Time : 2022/11/13 22:50:57
@Author : victor2022
@Desc : 清空数据
*/
void clear(int addr, int size)
{for (int i = addr; i <= addr+size; i++){EEPROM.write(i, 0);}EEPROMmit();
}
控制请求依然依靠http协议在客户端app和IOT设备之间进行传递,控制原理如下:
拿开关操作举例,当服务器的/power/
路径被访问时,就调用其对应的handler,向控制开关的io口发送一个低电平脉冲。代码如下:
// /power/路径对应的handler
void handlePower(){Serial.println("power ");switchPower();sendString("success");
}// 开关灯函数
void switchPower(){pulse(powerPin);
}// 向某io口发送低电平脉冲
void pulse(int pinNum){digitalWrite(pinNum, LOW);delay(30);flash();digitalWrite(pinNum, HIGH);
}
客户端app需要做到下面几件事:
app的页面布局如下图所示:
下面针对app的不同功能分别进行介绍。
扫描必须在手机连接wifi的情况下才能开始,在断开连接的情况下,点击上方的状态条开始扫描。设备扫描步骤如下:
/identity/
路径发送get请求,尝试获取信息 remote-controller
开头,则表明此主机就是我们要找的IOT设备,扫描结束,进入已连接状态。由于安卓不允许在主线程上进行网络请求操作,因此需要使用另一个线程处理扫描过程。另外,为了快速地扫描大量的主机,还需要使用线程池进行扫描速度优化。
在完成设备扫描后,可以通过规定好的api读取IOT设备的信息,并将这些信息保存在手机本地,方便下次开启应用时能够迅速地重新连接。
IOT设备信息包含连接状态、设备名称和设备ip地址,这些信息都比较简短,可以通过安卓原生提供的sharedPreference
来进行存储和读取。
除此之外,为了能够实时更新连接状态,app中还实现了心跳机制来检测连接的有效性,在检测到连接失效时,就会及时更新连接状态。
在完成连接之后,就可以通过Control Panel
中的操作按钮发送控制信号了。控制信号依然通过访问指定api的方式由http协议发送给IOT设备。
若想要进行进一步改造,需要在IOT设备中添加新的控制api,实现控制逻辑,并在客户端app中增加新的按钮,添加点击事件即可。
整个项目涉及了嵌入式、cpp开发(Arduino)、安卓开发等技术,但是整体难度不大。相关代码已经托管在了github上,带有签名的app也发布在了release中,项目地址:remote-controller。
有兴趣的同学可以玩一玩(拿来做课程设计也是极好的)。
由于我本人是Java选手,所以cpp代码都是最基础的函数调用,如果有同学有改进的想法,也欢迎一起参与这个项目。
本文发布于:2024-01-28 18:54:41,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064392869535.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |