-
Notifications
You must be signed in to change notification settings - Fork 117
/
Copy pathPAR_Monitoring.ino
355 lines (314 loc) · 9.18 KB
/
PAR_Monitoring.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/**
* @file PAR_Monitoring.ino
* @author rakwireless.com
* @brief This sketch demonstrate reading photosynthetically active radiation values
* and send the data to lora gateway.
* @version 0.1
* @date 2020-07-28
* @copyright Copyright (c) 2020
*/
#include <Arduino.h>
#include <ArduinoModbus.h> // Click here to get the library: http://librarymanager/All#ArduinoModbus
#include <LoRaWan-RAK4630.h> // Click here to get the library: http://librarymanager/All#SX126x
#include <SPI.h>
// Check if the board has an LED port defined
#ifndef LED_BUILTIN
#define LED_BUILTIN 35
#endif
#ifndef LED_BUILTIN2
#define LED_BUILTIN2 36
#endif
bool doOTAA = true; // OTAA is used by default.
#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 60 /**< Maximum number of events in the scheduler queue. */
#define LORAWAN_DATERATE DR_0
#define LORAWAN_TX_POWER TX_POWER_0
#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */
DeviceClass_t g_CurrentClass = CLASS_A;
LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_EU868; /* Region:EU868*/
lmh_confirm g_CurrentConfirm = LMH_UNCONFIRMED_MSG;
uint8_t g_AppPort = LORAWAN_APP_PORT;
/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
*/
static lmh_param_t g_lora_param_init = {
LORAWAN_ADR_ON,
LORAWAN_DATERATE,
LORAWAN_PUBLIC_NETWORK,
JOINREQ_NBTRIALS,
LORAWAN_TX_POWER,
LORAWAN_DUTYCYCLE_OFF
};
// Foward declaration
static void lorawan_has_joined_handler(void);
static void lorawan_join_failed_handler(void);
static void lorawan_rx_handler(lmh_app_data_t *app_data);
static void lorawan_confirm_class_handler(DeviceClass_t Class);
static void send_lora_frame(void);
/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
*/
static lmh_callback_t g_lora_callbacks = {
BoardGetBatteryLevel,
BoardGetUniqueId,
BoardGetRandomSeed,
lorawan_rx_handler,
lorawan_has_joined_handler,
lorawan_confirm_class_handler,
lorawan_join_failed_handler
};
//OTAA keys !!!! KEYS ARE MSB !!!!
uint8_t nodeDeviceEUI[8] = {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x33, 0x33};
uint8_t nodeAppEUI[8] = {0xB8, 0x27, 0xEB, 0xFF, 0xFE, 0x39, 0x00, 0x00};
uint8_t nodeAppKey[16] = {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88};
// ABP keys
uint32_t nodeDevAddr = 0x260116F8;
uint8_t nodeNwsKey[16] = {0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23};
uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C};
// Private defination
#define LORAWAN_APP_DATA_BUFF_SIZE 64 /**< buffer size of the data to be transmitted. */
#define LORAWAN_APP_INTERVAL 20000 /**< Defines for user timer, the application data transmission interval. 20s, value in [ms]. */
static uint8_t g_m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE]; //< Lora user application data buffer.
static lmh_app_data_t g_m_lora_app_data = {g_m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure.
TimerEvent_t g_appTimer;
static uint32_t timers_init(void);
static uint32_t g_count = 0;
static uint32_t g_count_fail = 0;
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Initialize Serial for debug output
time_t timeout = millis();
Serial.begin(115200);
while (!Serial)
{
if ((millis() - timeout) < 5000)
{
delay(100);
}
else
{
break;
}
}
// Initialize LoRa chip.
lora_rak4630_init();
Serial.println("=====================================");
Serial.println("Welcome to RAK4630 LoRaWan!!!");
if (doOTAA)
{
Serial.println("Type: OTAA");
}
else
{
Serial.println("Type: ABP");
}
switch (g_CurrentRegion)
{
case LORAMAC_REGION_AS923:
Serial.println("Region: AS923");
break;
case LORAMAC_REGION_AU915:
Serial.println("Region: AU915");
break;
case LORAMAC_REGION_CN470:
Serial.println("Region: CN470");
break;
case LORAMAC_REGION_CN779:
Serial.println("Region: CN779");
break;
case LORAMAC_REGION_EU433:
Serial.println("Region: EU433");
break;
case LORAMAC_REGION_IN865:
Serial.println("Region: IN865");
break;
case LORAMAC_REGION_EU868:
Serial.println("Region: EU868");
break;
case LORAMAC_REGION_KR920:
Serial.println("Region: KR920");
break;
case LORAMAC_REGION_US915:
Serial.println("Region: US915");
break;
case LORAMAC_REGION_RU864:
Serial.println("Region: RU864");
break;
case LORAMAC_REGION_AS923_2:
Serial.println("Region: AS923-2");
break;
case LORAMAC_REGION_AS923_3:
Serial.println("Region: AS923-3");
break;
case LORAMAC_REGION_AS923_4:
Serial.println("Region: AS923-4");
break;
}
Serial.println("=====================================");
if (!ModbusRTUClient.begin(9600))
{
Serial.println("Failed to start Modbus RTU Client!");
while (1)
;
}
Scheduler.startLoop(loop2);
//creat a user timer to send data to server period
uint32_t err_code;
err_code = timers_init();
if (err_code != 0)
{
Serial.printf("timers_init failed - %d\n", err_code);
return;
}
// Setup the EUIs and Keys
if (doOTAA)
{
lmh_setDevEui(nodeDeviceEUI);
lmh_setAppEui(nodeAppEUI);
lmh_setAppKey(nodeAppKey);
}
else
{
lmh_setNwkSKey(nodeNwsKey);
lmh_setAppSKey(nodeAppsKey);
lmh_setDevAddr(nodeDevAddr);
}
// Initialize LoRaWan
err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion);
if (err_code != 0)
{
Serial.printf("lmh_init failed - %d\n", err_code);
return;
}
// Start Join procedure
lmh_join();
}
void loop2()
{
short par;
uint32_t i = 0;
par = get_par();
g_m_lora_app_data.port = g_AppPort;
g_m_lora_app_data.buffer[i++] = 0x06;
g_m_lora_app_data.buffer[i++] = (par >> 8) & 0xFF;
g_m_lora_app_data.buffer[i++] = par & 0x00FF;
g_m_lora_app_data.buffsize = i;
delay(10000);
}
void loop()
{
// Put your application tasks here, like reading of sensors,
// Controlling actuators and/or other functions.
}
/**@brief LoRa function for handling HasJoined event.
*/
void lorawan_has_joined_handler(void)
{
if(doOTAA == true)
{
Serial.println("OTAA Mode, Network Joined!");
}
else
{
Serial.println("ABP Mode");
}
lmh_error_status ret = lmh_class_request(g_CurrentClass);
if (ret == LMH_SUCCESS)
{
delay(1000);
TimerSetValue(&g_appTimer, LORAWAN_APP_INTERVAL);
TimerStart(&g_appTimer);
}
}
/**@brief LoRa function for handling OTAA join failed
*/
static void lorawan_join_failed_handler(void)
{
Serial.println("OTAA join failed!");
Serial.println("Check your EUI's and Keys's!");
Serial.println("Check if a Gateway is in range!");
}
/**@brief Function for handling LoRaWan received data from Gateway
*
* @param[in] app_data Pointer to rx data
*/
void lorawan_rx_handler(lmh_app_data_t *app_data)
{
Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n",
app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer);
}
void lorawan_confirm_class_handler(DeviceClass_t Class)
{
Serial.printf("switch to class %c done\n", "ABC"[Class]);
// Informs the server that switch has occurred ASAP
g_m_lora_app_data.buffsize = 0;
g_m_lora_app_data.port = g_AppPort;
lmh_send(&g_m_lora_app_data, g_CurrentConfirm);
}
short get_par(void)
{
//Photosynthetically Active Radiation Sensor
short par;
/* RS485 Power On */
pinMode(WB_IO2, OUTPUT);
digitalWrite(WB_IO2, HIGH);
delay(100);
/* RS485 Power On */
if (!ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0x0006, 1))
{
Serial.print("failed to read registers! ");
Serial.println(ModbusRTUClient.lastError());
}
else
{
// If the request succeeds, the sensor sends the readings, that are
// stored in the holding registers. The read() method can be used to
// get the par values.
par = ModbusRTUClient.read();
Serial.printf("-------par------ = %d w/m2\n", par);
}
/* RS485 Power Off */
pinMode(WB_IO2, OUTPUT);
digitalWrite(WB_IO2, LOW);
delay(100);
/* RS485 Power Off */
return par;
}
void send_lora_frame(void)
{
short par;
if (lmh_join_status_get() != LMH_SET)
{
//Not joined, try again later
return;
}
lmh_error_status error = lmh_send(&g_m_lora_app_data, g_CurrentConfirm);
if (error == LMH_SUCCESS)
{
g_count++;
Serial.printf("lmh_send ok count %d\n", g_count);
}
else
{
g_count_fail++;
Serial.printf("lmh_send fail count %d\n", g_count_fail);
}
}
/**@brief Function for handling user timerout event.
*/
void tx_lora_periodic_handler(void)
{
TimerSetValue(&g_appTimer, LORAWAN_APP_INTERVAL);
TimerStart(&g_appTimer);
Serial.println("Sending frame now...");
send_lora_frame();
}
/**@brief Function for the Timer initialization.
*
* @details Initializes the timer module. This creates and starts application timers.
*/
uint32_t timers_init(void)
{
TimerInit(&g_appTimer, tx_lora_periodic_handler);
return 0;
}