/*
Set RTC & Send MQTT
BootMode = Compile Mode(Blink RedLED)
When you COMPLE skctch, it'll be this mode.
Connect to NTP Server & set RTC & go to
STANDBY mode & wake up.
Next mode is Reset Mode.
BootMode = Reset Mode(Blink BlueLED)
When you push RESET button, it'll be this mode.
Connect to MQTT Broker & Publish topic.
BootMode = Power On Mode(Blink GreenLED)
When you turn on board, it'll be this mode.
Initialize EEPROM & goto STANDBY mode & wake
up.
Next mode is Compile Mode.
PIN Connections (Using STM32F103):
W5X00 - STM32F103
---------------------
VCC - 3.3V
GND - GND
SS - Pin PA4
SCLK - Pin PA5
MISO - Pin PA6
MOSI - Pin PA7
RST - PullUp
*/
#include
<SPI.h>
#include <Ethernet_STM.h> //
https://github.com/rogerclarkmelbourne/Arduino_STM32
#include <EthernetUdp.h> //
https://github.com/rogerclarkmelbourne/Arduino_STM32
#include <PubSubClient.h> //
https://github.com/knolleary/pubsubclient
#include <STM32Sleep.h> //
https://github.com/chacal/stm32sleep
#include
<RTClock.h>
// https://github.com/rogerclarkmelbourne/Arduino_STM32/
#include <EEPROM.h>
RTClock rt (RTCSEL_LSE); // initialise
uint32 tt;
tm_t tm;
//#define EPSIZE 252
#define EPSIZE 250
#define Red PA0
#define Blue PA1
#define Green PA2
#define INTERVAL
10
#define MQTT_SERVER
"192.168.10.40"
//#define MQTT_SERVER
"broker.hivemq.com"
//#define MQTT_SERVER
"iot.eclipse.org"
#define MQTT_PORT 1883
#define MQTT_PUB_TOPIC
"stm32f103" // You can change
#define MQTT_WILL_TOPIC
"stm32f103" // You can change
#define MQTT_WILL_MSG "I am leaving..." // You
can change
#define TIME_ZONE +9
// You can change
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a
sticker on the shield
#if defined(WIZ550io_WITH_MACADDRESS) // Use assigned MAC
address of WIZ550io
;
#else
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xED};
#endif
unsigned int localPort =
8888; // local port to
listen for UDP packets
IPAddress timeServer(133, 243, 238, 164); // 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
EthernetUDP Udp;
EthernetClient ethClient;
PubSubClient pubsubClient(ethClient);
#define TCP 1
#define UDP 2
int execMode;
unsigned long lastTime = 0;
char clientid[30];
#if defined(W5100_ETHERNET_SHIELD)
char* shield = "W5100";
#else
char* shield = "W5500";
#endif
//Structure define of EEPROM(254Word)
struct EPROM{
tm_t tm; // Compile Date
& Time
uint16_t data[EPSIZE]; // User Data
};
const char *monthName[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
const char *dayName[7] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static void noop() {};
bool getTime(const char *str)
{
int Hour, Min, Sec;
if (sscanf(str, "%d:%d:%d", &Hour, &Min,
&Sec) != 3) return false;
tm.hour = Hour;
tm.minute = Min;
tm.second = Sec;
return true;
}
bool getDate(const char *str)
{
char Month[12];
int Day, Year;
uint8_t monthIndex;
if (sscanf(str, "%s %d %d", Month, &Day,
&Year) != 3) return false;
for (monthIndex = 0; monthIndex < 12;
monthIndex++) {
if (strcmp(Month,
monthName[monthIndex]) == 0) break;
}
if (monthIndex >= 12) return false;
tm.day = Day;
tm.month = monthIndex + 1;
tm.year = Year-1970;
tm.weekday = dow(Year,tm.month,tm.day);
return true;
}
// dow() [0-Sunday, 1-Monday etc.]
int dow(int y, int m, int d) {
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2,
4};
// y -= m < 3;
if (m < 3) y--;
return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
int readEPROM(EPROM* hoge, tm_t* cdate) {
uint16 AddressWrite = 0x10;
uint16 Status;
uint16 Data;
uint32_t crc32;
Serial.println("[readEPROM]");
Status = EEPROM.read(AddressWrite++, &Data);
if (Status != 0) return Status;
cdate->year = (Data >> 8) & 0xFF;
cdate->month = (Data >> 0) & 0xFF;
Status = EEPROM.read(AddressWrite++, &Data);
if (Status != 0) return Status;
cdate->day = (Data >> 8) & 0xFF;
cdate->weekday = (Data >> 0) & 0xFF;
Status = EEPROM.read(AddressWrite++, &Data);
if (Status != 0) return Status;
cdate->pm = (Data >> 8) & 0xFF;
cdate->hour = (Data >> 0) & 0xFF;
Status = EEPROM.read(AddressWrite++, &Data);
if (Status != 0) return Status;
cdate->minute = (Data >> 8) & 0xFF;
cdate->second = (Data >> 0) & 0xFF;
for(int i=0;i<EPSIZE;i++) {
Status = EEPROM.read(AddressWrite,
&Data);
if (Status != 0) return Status;
hoge->data[i] = Data;
AddressWrite++;
}
return 0;
}
int writeEPROM(EPROM* hoge, tm_t* cdate) {
uint16 AddressWrite = 0x10;
uint16 Status;
uint16 Data;
uint32_t crc32;
Serial.println("[writeEPROM]");
Data = (cdate->year << 8) +
cdate->month;
Status = EEPROM.write(AddressWrite++, Data);
if (Status != 0) return Status;
Data = (cdate->day << 8) +
cdate->weekday;
Status = EEPROM.write(AddressWrite++, Data);
if (Status != 0) return Status;
Data = (cdate->pm << 8) + cdate->hour;
Status = EEPROM.write(AddressWrite++, Data);
if (Status != 0) return Status;
Data = (cdate->minute << 8) +
cdate->second;
Status = EEPROM.write(AddressWrite++, Data);
if (Status != 0) return Status;
for(int i=0;i<EPSIZE;i++) {
Data = hoge->data[i];
Status = EEPROM.write(AddressWrite,
Data);
if (Status != 0) return Status;
AddressWrite++;
}
return 0;
}
void displayTM(char *title, tm_t hoge) {
Serial.print(title);
Serial.print(" year=");
Serial.print(hoge.year);
Serial.print(" monh=");
Serial.print(hoge.month);
Serial.print(" day=");
Serial.print(hoge.day);
Serial.print(" weekday=");
Serial.print(hoge.weekday);
Serial.print(" hour=");
Serial.print(hoge.hour);
Serial.print(" minute=");
Serial.print(hoge.minute);
Serial.print(" second=");
Serial.println(hoge.second);
}
int difftm(tm_t tm1, tm_t tm2) {
if (tm1.year != tm2.year) return 1;
if (tm1.month != tm2.month) return 1;
if (tm1.day != tm2.day) return 1;
if (tm1.weekday != tm2.weekday) return 1;
if (tm1.pm != tm2.pm) return 1;
if (tm1.hour != tm2.hour) return 1;
if (tm1.minute != tm2.minute) return 1;
if (tm1.second != tm2.second) return 1;
return 0;
}
void flashRed () {
digitalWrite(Red,!digitalRead(Red));
}
void flashBlue () {
digitalWrite(Blue,!digitalRead(Blue));
}
void flashGreen () {
digitalWrite(Green,!digitalRead(Green));
}
void errorDisplay(char* buff) {
int stat = 0;
Serial.print("Error:");
Serial.println(buff);
while(1) {
digitalWrite(Red,stat);
digitalWrite(Blue,stat);
digitalWrite(Green,stat);
stat = !stat;
delay(100);
}
}
void connectToServer() {
int retry = 0;
while(1) {
Serial.print("Attempting MQTT
connection ...");
if
(pubsubClient.connect(clientid,MQTT_WILL_TOPIC,0,0,MQTT_WILL_MSG))
break;
Serial.println("connect Fail");
delay(5000);
retry++;
if (retry > 100)
errorDisplay("connect retry over!!");
}
Serial.println("connected");
}
void setup() {
struct EPROM romData;
tt = rt.getTime();
delay(1000);
Serial.begin(9600);
pinMode(Blue,OUTPUT);
pinMode(Red,OUTPUT);
pinMode(Green,OUTPUT);
digitalWrite(Blue,LOW);
digitalWrite(Red,LOW);
digitalWrite(Green,LOW);
if (tt != 0) { // Reset
tm_t cdate;
readEPROM(&romData,&cdate);
displayTM("[cdate]",cdate);
Serial.print("__TIME__=[");
Serial.print(__TIME__);
Serial.print("] __DATE__=[");
Serial.print(__DATE__);
Serial.println("]");
// get the date and time the compiler
was run
if (getDate(__DATE__) &&
getTime(__TIME__)) {
displayTM("[tm]",tm);
}
if (difftm(cdate, tm) == 0) { // Reset
Serial.println("Compile
date is MUCH!!");
execMode = TCP;
rt.attachSecondsInterrupt(flashBlue);
} else { // Compile
execMode = UDP;
Serial.println("Compile
date is NOT MUCH!!");
writeEPROM(&romData,&tm);
for(int i=0;i<20;i++) {
digitalWrite(Red,HIGH);
delay(50);
digitalWrite(Red,LOW);
delay(50);
}
//
rt.attachSecondsInterrupt(flashRed);
}
} else { // Power ON
// execMode = UDP;
Serial.println("RTC is CLEAR!!");
tm.year=0;
writeEPROM(&romData,&tm);
for(int i=0;i<20;i++) {
digitalWrite(Green,HIGH);
delay(50);
digitalWrite(Green,LOW);
delay(50);
}
//
rt.attachSecondsInterrupt(flashGreen);
rt.createAlarm(&noop, rt.getTime()
+ 5);
goToSleep(STANDBY);
}
// start Ethernet
#if defined(WIZ550io_WITH_MACADDRESS)
if (Ethernet.begin() == 0) {
#else
if (Ethernet.begin(mac) == 0) {
#endif
Serial.println("Failed to configure
Ethernet using DHCP");
// no point in carrying on, so do
nothing forevermore:
for(;;)
;
}
Serial.print("My IP: ");
Serial.println(Ethernet.localIP());
Serial.print("Netmask: ");
Serial.println(Ethernet.subnetMask());
Serial.print("GW IP: ");
Serial.println(Ethernet.gatewayIP());
Serial.print("DNS IP: ");
Serial.println(Ethernet.dnsServerIP());
if (execMode == UDP) {
Serial.println("UDP Mode");
Udp.begin(localPort);
while (1) {
Serial.println("UDP packet
send");
sendNTPpacket(timeServer);
// send an NTP packet to a time server
delay(1000);
if ( Udp.parsePacket() ) {
break;
}
delay(10000);
}
Serial.println("UDP packet receive");
// 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;
Serial.print("Seconds since Jan 1 1900
= " );
Serial.println(secsSince1900);
// 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:
unsigned long epoch = secsSince1900 -
seventyYears;
// print Unix time:
Serial.print("Unix time = ");
Serial.println(epoch);
rt.setTime(epoch);
tt = rt.getTime();
Serial.print("The UNIX Time is ");
Serial.print(rt.year()+1970);
Serial.print('/');
Serial.print(rt.month());
Serial.print('/');
Serial.print(rt.day());
Serial.print(' ');
Serial.print(rt.hour());
Serial.print(':');
Serial.print(rt.minute());
Serial.print(':');
Serial.println(rt.second());
Serial.println();
time_t
localTime;
localTime = rt.TimeZone(tt,TIME_ZONE);
// Get Local Time
Serial.print("Local Time = ");
Serial.println(tt);
rt.setTime(localTime); // 日本時間を設定
Serial.print("The Local Time is ");
Serial.print(rt.year()+1970);
Serial.print('/');
Serial.print(rt.month());
Serial.print('/');
Serial.print(rt.day());
Serial.print(' ');
Serial.print(rt.hour());
Serial.print(':');
Serial.print(rt.minute());
Serial.print(':');
Serial.println(rt.second());
Serial.println();
rt.createAlarm(&noop, rt.getTime()
+ 5);
goToSleep(STANDBY);
while(1) {}
} else {
Serial.println("TCP Mode");
pubsubClient.setServer(MQTT_SERVER,
MQTT_PORT);
// char clientid[30];
IPAddress ip = Ethernet.localIP();
Serial.print(ip[0]);
Serial.print(".");
Serial.print(ip[1]);
Serial.print(".");
Serial.print(ip[2]);
Serial.print(".");
Serial.println(ip[3]);
//
sprintf(clientid,"STM32-%03d-%03d-%03d-%03d",(int)ip[0],(int)ip[1],(int)ip[2],(int)ip[3]);
sprintf(clientid,"STM32-%03d",(int)ip[3]);
Serial.print("clientid=");
Serial.println(clientid);
#if 0
Serial.print("Attempting MQTT
connection...");
// Attempt to connect
if
(!pubsubClient.connect(clientid,MQTT_WILL_TOPIC,0,0,MQTT_WILL_MSG))
{
errorDisplay("connect
Fail");
}
Serial.println("connected");
#endif
lastTime = millis();
}
}
void loop(){
static int counter=0;
static int value = 0;
char payload[75];
if (!pubsubClient.connected()) {
connectToServer();
snprintf (payload, 75, "clientid:%s
shield:%s connected...",clientid,shield);
if
(!pubsubClient.publish(MQTT_PUB_TOPIC, payload)) {
errorDisplay("publish
fail");
}
}
pubsubClient.loop();
long now = millis();
if (now - lastTime > 1000) {
lastTime = now;
counter++;
if (counter > INTERVAL) {
++value;
// snprintf (payload, 75,
"I'm STM32F103 Local Time = %0d/%0d/%0d %02d:%02d:%02d",
snprintf (payload, 75, "I'm
%s : Local Time = %0d/%0d/%0d %02d:%02d:%02d",
clientid,
rt.year()+1970,
rt.month(),
rt.day(),
rt.hour(),
rt.minute(),
rt.second());
Serial.print("Publish
message: ");
Serial.println(payload);
if
(!pubsubClient.publish(MQTT_PUB_TOPIC, payload)) {
errorDisplay("publish fail");
}
counter=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();
}
|