资料介绍
描述
如果你有一只物联网宠物,它会吃什么?WiFi SSID,当然!
Nerd 是一种无线电子宠物,它通过收集 WiFi SSID 以及一些休息和阳光来生存。
为了让它茁壮成长,你必须平衡离线和在线模式与光明和黑暗,以确保它有一个适当的日常吃-睡-书呆子程序。
如果没有 WiFi 太久,它将使用其内置的压电扬声器以摩尔斯电码发送 SOS。离线时间越长,蜂鸣声越多。
简而言之
书呆子将每半小时醒来一次以扫描周围的网络。如果它检测到新网络,它将存储它们并在低功耗模式下重新进入睡眠状态(以节省电池寿命)。否则它会用蜂鸣器发出噪音来抱怨,直到你喂它或把它放在黑暗中。
它还会通过连接到您的 wifi 网络了解何时在家。在家时,Nerd 将能够连接到互联网并获取当前时间和日期。
如果超过两天不喂,它会急剧死亡,发出很大的噪音。
成分
- RGB LED
- 蜂鸣器
- 电池
- 220欧姆电阻
学习目标
- 管理完整的 WiFi 功能
- 在闪存中存储数据
- 管理时间和实时时钟
- 管理低功耗模式
想知道更多?
本教程是让您熟悉 MKR1000 和 IoT 的一系列实验的一部分。所有实验都可以使用 MKR IoT Bundle 中包含的组件构建。
- 书呆子
设立董事会
为了实现所有功能,我们将使用以下库:
- WiFi101 //连接到互联网并扫描网络
- FlashStorage // 保存值,以便它们不会在每次重新启动时被擦除
- RTCZero // 管理时间触发事件
- ArduinoLowPower //节省电池电量
- WiFiUdp // 从互联网上获取时间和日期
扫描 WiFi 网络
书呆子渴望网络!
扫描网络非常简单, 只需上传此示例草图或转到> 示例 > WiFi101 > ScanNetworksAdvanced以获得更多扩展版本。
#include
#include
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// scan for existing networks:
Serial.println();
Serial.println("Scanning available networks...");
listNetworks();
}
void loop() {
delay(10000);
// scan for existing networks:
Serial.println("Scanning available networks...");
listNetworks();
}
void listNetworks() {
// scan for nearby networks:
Serial.println("** Scan Networks **");
int numSsid = WiFi.scanNetworks();
if (numSsid == -1)
{
Serial.println("Couldn't get a WiFi connection");
while (true);
}
// print the list of networks seen:
Serial.print("number of available networks: ");
Serial.println(numSsid);
// print the network number and name for each network found:
for (int thisNet = 0; thisNet < numSsid; thisNet++) {
Serial.print(thisNet + 1);
Serial.print(" SSID: ");
Serial.println(WiFi.SSID(thisNet));
Serial.flush();
}
Serial.println();
}
在闪存中存储值
当然,您不希望书呆子每次没电时就死掉!
为了避免这种行为,我们将在闪存中保存一些变量(作为食物量),以便即使在电路板关闭并再次打开后也可以检索它们。
您可以使用以下方法了解基本功能:
示例 > FlashStorage > FlashStoreAndRetrieve
我们将保存网络的名称,以便书呆子只吃一次,我们还将使用保存这些 SSID 的数组来计算它在白天吃的食物量。
保存在闪存中的值将在电路板重置后保留,但不会在新草图的上传后保留。每次上传新草图时,闪存也会被清空。
此草图将扫描网络并将 SSID 保存在闪存中。
#include
#include
#include
#define MAGIC_NUMBER 0x7423 // arbitrary number to double check the saved SSID
#define MaxNet 30 // max amount of network to be saved
int PosToBeSaved = 0; // Variable used to navigate the array of networks
int daily_amount_of_food = 12; // The amount of food per day needed to survive
// Struct of variable to be saved in flash memory
typedef struct {
int magic;
boolean valid[MaxNet];
char SSIDs[MaxNet][100];
} Networks;
FlashStorage(my_flash_store, Networks);
Networks values;
void setup() {
Serial.begin(115200);
while(!Serial); // wait until the Serial montior has be opened
delay(2000);
values = my_flash_store.read(); // Read values from flash memory
if (values.magic == MAGIC_NUMBER) { // If token is correct print saved networks
Serial.println("saved data:");
Serial.println("");
for (int a = 0; a < MaxNet; a++) {
if (values.valid[a]) {
Serial.println(values.SSIDs[a]);
} else {
PosToBeSaved = a;
}
}
}
}
void loop() {
// Temporarly save the number of networks
int networks_already_saved = PosToBeSaved;
getNetwork();
if (PosToBeSaved >= daily_amount_of_food) {
Serial.println("Enough food for today");
}
delay(5000);
}
// Feed the Nerd with networks's SSID
void getNetwork() {
// scan for nearby networks:
Serial.println("\n*Scan Networks*\n");
int numSsid = WiFi.scanNetworks();
delay(1000);
if (numSsid == -1)
{
Serial.println("There are no WiFi networks here..");
} else {
Serial.print("number of available networks: ");
Serial.println(numSsid);
// print the network number and name for each network found:
for (int thisNet = 0; thisNet < numSsid; thisNet++) {
Serial.print("SSID: ");
Serial.println(WiFi.SSID(thisNet));
delay(500);
char* net = WiFi.SSID(thisNet);
bool canBeSaved = true;
// check if the network has already been saved
for (int a = 0; a < PosToBeSaved ; a++) {
if (values.valid[a]) {
if (strncmp(net, values.SSIDs[a], 100) == 0 || strnlen(net, 100) == 0) {
Serial.println("Not saved");
canBeSaved = false;
}
}
}
// Store ssid name
if (canBeSaved && PosToBeSaved < MaxNet) {
if (strlen(net) + 1 < 100 && strlen(net) > 0) { // check if the SSID name fits 100 bytes
memset(values.SSIDs[PosToBeSaved], 0, sizeof(values.SSIDs[PosToBeSaved])); // set all characters to zero
memcpy(values.SSIDs[PosToBeSaved], net, strlen(net) + 1); // copy "net" to values.SSDs[thisNet]
values.valid[PosToBeSaved] = true;
values.magic = MAGIC_NUMBER;
my_flash_store.write(values);
Serial.println(String(values.SSIDs[PosToBeSaved]) + " saved in position " + String(PosToBeSaved));
PosToBeSaved ++;
}
else {
Serial.println(" network skipped");
}
}
}
}
}
请注意我们如何定义可以保存的最大网络数量,以避免内存空间问题:
#define MaxNet 30
int PosToBeSaved = 0;
已用于导航保存网络名称的数组并测量已吃的食物量。
管理时间
我们可以将实时时钟 (RTC) 的功能与 WiFi 相结合,以获取当前时间和日期,然后设置板的内部时钟。通过这种方式,我们可以在很长一段时间内触发基于时间的事件,而无需使用millis()
当您必须将毫秒转换为天时可能会很棘手的函数。
我们将从网络时间协议(NTP) 时间服务器获取时间,然后使用它设置 RTC。请注意,收到的时间采用纪元格式,即自 1970 年 1 月 1 日以来的秒数。
您可以从example > WiFi101 > WiFiUdpNtpClient运行基本草图
在下面的草图中,我们将事物放在一起:扫描网络功能和与时间相关的功能。
-
bool atHome = false;
用于触发 WiFi 连接,因此请求服务器获取时间。
-
check_home()
用于扫描所有可用网络并查看其中一个是否为家庭 WiFi 网络。
-
connect_WiFi()
然后调用,它将板连接到 WiFi,触发对服务器的请求并打印当前时间。
-
rtc.setEpoch(epoch + GMT);
用于以纪元格式以当前时间启动 RTC,修改 GMT 变量以将时间调整为您当前的时区。
#include
#include
#include
#include
#include
WiFiUDP udp;
WiFiUDP Udp;
RTCZero rtc;
#define MAGIC_NUMBER 0x7423 // arbitrary number to double check the saved SSID
#define MaxNet 30 // max amount of network to be saved
const char* home_ssid = SECRET_SSID; // your network SSID (name)
const char* password = SECRET_PSWD; // your network password
int PosToBeSaved = 0; // Variable used to navigate the array of networks
int daily_amount_of_food = 12; // The amount of food per day needed to survive
bool atHome = false;
// Struct of variable to be saved in flash memory
typedef struct {
int magic;
boolean valid[MaxNet];
char SSIDs[MaxNet][100];
int alive_days;
int last_time_feeded;
} Networks;
FlashStorage(my_flash_store, Networks);
Networks values;
void setup() {
Serial.begin(115200);
delay(2000);
rtc.begin(); // enable real time clock functionalities
values = my_flash_store.read(); // Read values from flash memory
if (values.magic == MAGIC_NUMBER) { // If token is correct print saved networks
Serial.println("saved data:");
Serial.println("");
for (int a = 0; a < MaxNet; a++) {
if (values.valid[a]) {
Serial.println(values.SSIDs[a]);
} else {
PosToBeSaved = a;
}
}
}
}
void loop() {
if(!atHome) check_home();
// Temporarly save the number of networks
int networks_already_saved = PosToBeSaved;
getNetwork();
if (PosToBeSaved >= daily_amount_of_food) {
Serial.println("Enough food for today");
}
}
void check_home() {
int numSsid = WiFi.scanNetworks();
if (numSsid != -1) {
for (int thisNet = 0; thisNet < numSsid; thisNet++) {
delay(100);
if (strncmp(WiFi.SSID(thisNet), home_ssid, 100) == 0) {
Serial.println("Yay, I'm home \n");
atHome = true;
connect_WiFi();
}
}
}
}
void connect_WiFi() {
if (WiFi.status() != WL_CONNECTED) {
while (WiFi.begin(home_ssid, password) != WL_CONNECTED) {
delay(500);
}
Serial.println("WiFi connected \n");
GetCurrentTime();
printTime();
}
}
// Feed the Nerd with networks's SSID
void getNetwork() {
// scan for nearby networks:
Serial.println("*Scan Networks*");
int numSsid = WiFi.scanNetworks();
delay(1000);
if (numSsid == -1)
{
Serial.println("There are no WiFi networks here..");
} else {
Serial.print("number of available networks: ");
Serial.println(numSsid);
// print the network number and name for each network found:
for (int thisNet = 0; thisNet < numSsid; thisNet++) {
Serial.print("SSID: ");
Serial.println(WiFi.SSID(thisNet));
delay(500);
char* net = WiFi.SSID(thisNet);
bool canBeSaved = true;
// check if the network has already been saved
for (int a = 0; a < PosToBeSaved ; a++) {
if (values.valid[a]) {
if (strncmp(net, values.SSIDs[a], 100) == 0 || strnlen(net, 100) == 0) {
Serial.println("Not saved");
canBeSaved = false;
}
}
}
// Store ssid name
if (canBeSaved && PosToBeSaved < MaxNet) {
if (strlen(net) + 1 < 100 && strlen(net) > 0) { // check if the SSID name fits 100 bytes
memset(values.SSIDs[PosToBeSaved], 0, sizeof(values.SSIDs[PosToBeSaved])); // set all characters to zero
memcpy(values.SSIDs[PosToBeSaved], net, strlen(net) + 1); // copy "net" to values.SSDs[thisNet]
values.valid[PosToBeSaved] = true;
values.last_time_feeded = rtc.getEpoch();
values.magic = MAGIC_NUMBER;
my_flash_store.write(values);
Serial.println(String(values.SSIDs[PosToBeSaved]) + " saved in position " + String(PosToBeSaved));
PosToBeSaved ++;
}
else {
Serial.println(" network skipped");
}
}
}
}
}
/*************************************************
Start an UDP connection to get the time in unix,
then set the real time clock (rtc)
************************************************/
unsigned int localPort = 2390; // local port to listen for UDP packets
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
const int GMT = 1 * 60 * 60; //change this to adapt it to your time zone hours*minutes*seconds
unsigned long epoch;
void GetCurrentTime() {
int numberOfTries = 0, maxTries = 6;
do {
epoch = readLinuxEpochUsingNTP();
numberOfTries++;
}
while ((epoch == 0) || (numberOfTries > maxTries));
if (numberOfTries > maxTries) {
Serial.print("NTP unreachable!!");
while (1);
}
else {
Serial.print("Epoch received: ");
Serial.println(epoch);
rtc.setEpoch(epoch + GMT);
Serial.println();
}
}
unsigned long readLinuxEpochUsingNTP()
{
Udp.begin(localPort);
sendNTPpacket(timeServer); // send an NTP packet to a time server
// wait to see if a reply is available
delay(1000);
if ( Udp.parsePacket() ) {
Serial.println("NTP time received");
// We've received a packet, read the data from it
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
// now convert NTP time into everyday time:
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
Udp.stop();
return (secsSince1900 - seventyYears);
}
else {
Udp.stop();
return 0;
}
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress & address)
{
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
void printTime() {
// Print date...
Serial.print(rtc.getDay());
Serial.print(" / ");
Serial.print(rtc.getMonth());
Serial.print(" / ");
Serial.print(rtc.getYear());
Serial.print("\t");
// ...and time
print2digits(rtc.getHours());
Serial.print(": ");
print2digits(rtc.getMinutes());
Serial.print(": ");
print2digits(rtc.getSeconds());
Serial.println("");
}
void print2digits(int number) {
if (number < 10) {
Serial.print("0");
}
Serial.print(number);
实现当前时间允许我们使用像这样的简单函数来管理 Nerd 的生死:
if(rtc.getEpoch() - values.last_time_fed >= 86400*2){
// complain and eventually die :(
}
其中86400
是一天中的秒数, values.last_time_fed
是以纪元格式存储的时间值,其中 Nerd 上次被喂食并以纪元格式rtc.getEpoch()
返回当前时间。
低功耗模式
我们可以使用低功耗模式让我们的电路板进入睡眠状态。这意味着它将禁用其大部分功能(包括 WiFi)以节省电池电量。
由于我们希望 Nerd 定期醒来,我们可以轻松设置一个计时器:
#include "ArduinoLowPower.h"
int sleeping_time = 5000; // 5 seconds
bool awake = true;
void setup() {
Serial.begin(9600);
LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, WakeUp, CHANGE);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
if (awake) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
awake = false;
Serial.println("going to sleep");
LowPower.sleep(sleeping_time);
}
void WakeUp() {
Serial.println("awake");
awake = true;
}
请注意,该WakeUp()
函数附加到中断,这意味着它不能包含任何包含延迟的代码。但是我们可以设置布尔变量来触发循环中的事件。
- 宠物食品分配器开源设计
- 宠物喂食器开源硬件
- 自动宠物喂食器开源硬件
- 宠物食品消费追踪器开源分享
- 赫伯特机器人虚拟宠物开源分享
- HugWear可穿戴宠物开源分享
- 无线电广播TA2003开源分享
- 自制无线电通信开源项目
- 带TEF6686的RDS无线电开源
- 无线电控制椰子收割机开源分享
- 对于减量AGC无线电开源项目
- 无线电控制车开源项目
- 解析无线电伪码测目标距离系统的设计 0次下载
- 软件无线电基础 50次下载
- 软件无线电RFID测试平台课件下载 32次下载
- 无线电时钟的dcf信号是什么意思 130次阅读
- 厨房内的无线电源解决方案 278次阅读
- 软件无线电安全之GNU Radio基础知识 3079次阅读
- 什么是无线电频谱 最全最新无线通信频率分配 8359次阅读
- 两种常见无线电架构对比 771次阅读
- X和Ku-频段小型无线电设计 1070次阅读
- 无线电力传输 1972次阅读
- 无线电信号的发送和接收 1.5w次阅读
- 带你了解无线电遥控技术 9902次阅读
- 软件无线电架构的详细概述 1.6w次阅读
- 基于Zedboard的开源软件定义无线电设备——Panoradio 6311次阅读
- 基于FPGA的软件无线电平台设计详细教程 3411次阅读
- 基于SDR技术的无线电设计方法 1533次阅读
- 软件定义无线电的创新应用 2009次阅读
- 简易无线电接收器电路 1.2w次阅读
下载排行
本周
- 1山景DSP芯片AP8248A2数据手册
- 1.06 MB | 532次下载 | 免费
- 2RK3399完整板原理图(支持平板,盒子VR)
- 3.28 MB | 339次下载 | 免费
- 3TC358743XBG评估板参考手册
- 1.36 MB | 330次下载 | 免费
- 4DFM软件使用教程
- 0.84 MB | 295次下载 | 免费
- 5元宇宙深度解析—未来的未来-风口还是泡沫
- 6.40 MB | 227次下载 | 免费
- 6迪文DGUS开发指南
- 31.67 MB | 194次下载 | 免费
- 7元宇宙底层硬件系列报告
- 13.42 MB | 182次下载 | 免费
- 8FP5207XR-G1中文应用手册
- 1.09 MB | 178次下载 | 免费
本月
- 1OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234315次下载 | 免费
- 2555集成电路应用800例(新编版)
- 0.00 MB | 33566次下载 | 免费
- 3接口电路图大全
- 未知 | 30323次下载 | 免费
- 4开关电源设计实例指南
- 未知 | 21549次下载 | 免费
- 5电气工程师手册免费下载(新编第二版pdf电子书)
- 0.00 MB | 15349次下载 | 免费
- 6数字电路基础pdf(下载)
- 未知 | 13750次下载 | 免费
- 7电子制作实例集锦 下载
- 未知 | 8113次下载 | 免费
- 8《LED驱动电路设计》 温德尔著
- 0.00 MB | 6656次下载 | 免费
总榜
- 1matlab软件下载入口
- 未知 | 935054次下载 | 免费
- 2protel99se软件下载(可英文版转中文版)
- 78.1 MB | 537798次下载 | 免费
- 3MATLAB 7.1 下载 (含软件介绍)
- 未知 | 420027次下载 | 免费
- 4OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234315次下载 | 免费
- 5Altium DXP2002下载入口
- 未知 | 233046次下载 | 免费
- 6电路仿真软件multisim 10.0免费下载
- 340992 | 191187次下载 | 免费
- 7十天学会AVR单片机与C语言视频教程 下载
- 158M | 183279次下载 | 免费
- 8proe5.0野火版下载(中文版免费下载)
- 未知 | 138040次下载 | 免费
评论
查看更多