Version 5.3.1; support for T_Beam ESP32, inclding ensor support for GPS and battery, 433MHz support and several bugfixes
rodzic
e179c0a9d4
commit
b59250e29b
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -1,6 +1,6 @@
|
|||
# Single Channel LoRaWAN Gateway
|
||||
|
||||
Version 5.2.0, May 30, 2018
|
||||
Version 5.3.1, June 30, 2018
|
||||
Author: M. Westenberg (mw12554@hotmail.com)
|
||||
Copyright: M. Westenberg (mw12554@hotmail.com)
|
||||
|
||||
|
@ -16,6 +16,23 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
|
|||
|
||||
# Release Notes
|
||||
|
||||
New features in version 5.3.1 (June 30, 2018)
|
||||
- Included support for T-Beam board including on board GPS sensor (_sensor.ino). #define GATEWAYNODE 1 will
|
||||
turn the gateway into a node as well. Remember to set the address etc in ESP-sc-gway.h.
|
||||
- First version to explore possibilities of 433 MHz LoRa frequencies.
|
||||
Included _LFREQ setting in the ESP-sc-gway.h file
|
||||
- Changes to the WiFi inplementation. The gateway does now store the SSID and poassword.
|
||||
-
|
||||
|
||||
New features in version 5.3.0 (June 20, 2018)
|
||||
- Connect to both public and private routers
|
||||
|
||||
|
||||
New features in version 5.2.1 (June 6, 2018)
|
||||
- Repair the downlink functions
|
||||
- Repair sersor functions
|
||||
- Bufgixes
|
||||
|
||||
New features in version 5.2.0 (May 30, 2018)
|
||||
- Enable support for ESP32 from TTGO, several code changes where ESP32 differs from ESP8266.
|
||||
OLED is supported but NOT tested. Some hardware specific reporting functions of the WebGUI do not work yet.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1 H
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1 H
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway and many others.
|
||||
// Contibutions of Dorijan Morelj and Andreas Spies for OLED support.
|
||||
|
@ -19,7 +19,7 @@
|
|||
//
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
#define VERSION "V.5.2.1.H; 180606a"
|
||||
#define VERSION "V.5.3.1.H; 180630a"
|
||||
|
||||
// This value of DEBUG determines whether some parts of code get compiled.
|
||||
// Also this is the initial value of debug parameter.
|
||||
|
@ -37,7 +37,11 @@
|
|||
// This is usually a good idea if the webserver is interrupted halfway a writing
|
||||
// operation.
|
||||
// Normally, value 0 is a good default.
|
||||
#define SPIFF_FORMAT 0
|
||||
#define _SPIFF_FORMAT 0
|
||||
|
||||
// Define the LoRa Frequncy band that is used. TTN Supported values are 925MHz, 868MHz and 433MHz.
|
||||
// So supported values are: 433 868 915
|
||||
#define _LFREQ 868
|
||||
|
||||
// The spreading factor is the most important parameter to set for a single channel
|
||||
// gateway. It specifies the speed/datarate in which the gateway and node communicate.
|
||||
|
@ -78,8 +82,9 @@
|
|||
// 1: HALLARD
|
||||
// 2: COMRESULT pin out
|
||||
// 3: ESP32 Wemos pin out
|
||||
// 4: ESP32 TTGO pinning
|
||||
// 5: Other, define your own in loraModem.h
|
||||
// 4: ESP32 TTGO pinning (should work for 433 and OLED too).
|
||||
// 5: ESP32 TTGO EU433 MHz with OLED
|
||||
// 6: Other, define your own in loraModem.h
|
||||
#define _PIN_OUT 1
|
||||
|
||||
// Gather statistics on sensor and Wifi status
|
||||
|
@ -112,14 +117,6 @@
|
|||
// getting WiFi SSID and password using WiFiManager)
|
||||
#define AP_NAME "YourName"
|
||||
#define AP_PASSWD "YourPassword"
|
||||
|
||||
|
||||
// Defines whether the gateway will also report sensor/status value on MQTT
|
||||
// after all, a gateway can be a node to the system as well
|
||||
// Set its LoRa address and key below in this file
|
||||
// See spec. para 4.3.2
|
||||
#define GATEWAYNODE 0
|
||||
#define _CHECK_MIC 0
|
||||
|
||||
// This section defines whether we use the gateway as a repeater
|
||||
// For his, we use another output channle as the channel (default==0) we are
|
||||
|
@ -185,8 +182,8 @@
|
|||
// Port is UDP port in this program
|
||||
//
|
||||
// Default for testing: Switched off
|
||||
#define _THINGPORT <port> // dash.westenberg.org:8057
|
||||
#define _THINGSERVER "<dns.server.com>" // Server URL of the LoRa-udp.js handler
|
||||
//#define _THINGPORT <port> // e.g. 1700
|
||||
//#define _THINGSERVER "<dns.server.com>" // Server URL of the LoRa-udp.js handler
|
||||
|
||||
// Gateway Ident definitions
|
||||
#define _DESCRIPTION "ESP Gateway" // Name of the gateway
|
||||
|
@ -203,11 +200,22 @@
|
|||
#define SECS_IN_HOUR 3600
|
||||
#define NTP_INTR 0 // Do NTP processing with interrupts or in loop();
|
||||
|
||||
|
||||
// Defines whether the gateway will also report sensor/status value on MQTT
|
||||
// after all, a gateway can be a node to the system as well
|
||||
// Set its LoRa address and key below in this file
|
||||
// See spec. para 4.3.2
|
||||
#define GATEWAYNODE 0
|
||||
#define _CHECK_MIC 0
|
||||
|
||||
#if GATEWAYNODE==1
|
||||
#define _DEVADDR { 0x26, 0x01, 0x01, 0x01 }
|
||||
#define _APPSKEY { 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
#define _NWKSKEY { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
#define _SENSOR_INTERVAL 300
|
||||
// For ESP32 based TTGO boards these two are normally included
|
||||
#define _GPS 0
|
||||
#define _BATTERY 0
|
||||
#endif
|
||||
|
||||
// Define the correct radio type that you are using
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
// Author: Maarten Westenberg (mw12554@hotmail.com)
|
||||
//
|
||||
// Based on work done by Thomas Telkamp for Raspberry PI 1-ch gateway and many others.
|
||||
|
@ -102,12 +102,19 @@ extern "C" {
|
|||
#include <ArduinoOTA.h>
|
||||
#endif//OTA
|
||||
|
||||
#endif//PIN_OUT>=3
|
||||
#endif//ESP_ARCH
|
||||
|
||||
|
||||
uint8_t debug=1; // Debug level! 0 is no msgs, 1 normal, 2 extensive
|
||||
uint8_t pdebug=0xFF; // Allow all atterns (departments)
|
||||
|
||||
#if GATEWAYNODE==1
|
||||
#if _GPS==1
|
||||
#include <TinyGPS++.h>
|
||||
TinyGPSPlus gps;
|
||||
HardwareSerial Serial1(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// You can switch webserver off if not necessary but probably better to leave it in.
|
||||
#if A_SERVER==1
|
||||
#if ESP32_ARCH==1
|
||||
|
@ -467,6 +474,7 @@ int readUdp(int packetSize)
|
|||
uint8_t buff[32]; // General buffer to use for UDP, set to 64
|
||||
uint8_t buff_down[RX_BUFF_SIZE]; // Buffer for downstream
|
||||
|
||||
// if ((WiFi.status() != WL_CONNECTED) &&& (WlanConnect(10) < 0)) {
|
||||
if (WlanConnect(10) < 0) {
|
||||
#if DUSB>=1
|
||||
Serial.print(F("readdUdp: ERROR connecting to WLAN"));
|
||||
|
@ -962,12 +970,30 @@ void setup() {
|
|||
Serial.begin(_BAUDRATE); // As fast as possible for bus
|
||||
delay(100);
|
||||
|
||||
#if _GPS==1
|
||||
// Pins are define in LoRaModem.h together with other pins
|
||||
Serial1.begin(9600, SERIAL_8N1, GPS_TX, GPS_RX);// PIN 12-TX 15-RX
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
Serial.println(F("ESP32 defined"));
|
||||
#if DUSB>=1
|
||||
Serial.print(F("ESP32 defined, freq="));
|
||||
#if _LFREQ==433
|
||||
Serial.print(freqs[0]);
|
||||
Serial.print(F(" EU433"));
|
||||
#elif _LFREQ==868
|
||||
Serial.print(freqs[0]);
|
||||
Serial.print(F(" EU868"));
|
||||
#endif
|
||||
Serial.println();
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#if DUSB>=1
|
||||
Serial.println(F("ARDUINO_ARCH_ESP32 defined"));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if DUSB>=1
|
||||
Serial.flush();
|
||||
|
@ -980,7 +1006,7 @@ void setup() {
|
|||
else {
|
||||
}
|
||||
#endif
|
||||
#if SPIFF_FORMAT>=1
|
||||
#if _SPIFF_FORMAT>=1
|
||||
#if DUSB>=1
|
||||
if (( debug >= 0 ) && ( pdebug & P_MAIN )) {
|
||||
Serial.println(F("Format Filesystem ... "));
|
||||
|
@ -1016,7 +1042,8 @@ void setup() {
|
|||
#endif
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin();
|
||||
WiFi.setAutoConnect(true);
|
||||
//WiFi.begin();
|
||||
|
||||
WlanReadWpa(); // Read the last Wifi settings from SPIFFS into memory
|
||||
|
||||
|
@ -1032,13 +1059,14 @@ void setup() {
|
|||
// We start by connecting to a WiFi network, set hostname
|
||||
char hostname[12];
|
||||
|
||||
// Setup WiFi UDP connection. Give it some time and retry 50 times..
|
||||
while (WlanConnect(50) < 0) {
|
||||
// Setup WiFi UDP connection. Give it some time and retry x times..
|
||||
while (WlanConnect(0) <= 0) {
|
||||
Serial.print(F("Error Wifi network connect "));
|
||||
Serial.println();
|
||||
yield();
|
||||
}
|
||||
|
||||
// After there is a WiFi router connection, we can also set the hostname.
|
||||
#if ESP32_ARCH==1
|
||||
sprintf(hostname, "%s%02x%02x%02x", "esp32-", MAC_array[3], MAC_array[4], MAC_array[5]);
|
||||
WiFi.setHostname( hostname );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
@ -15,8 +15,109 @@
|
|||
//
|
||||
// This file contains the LoRa filesystem specific code
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WLANSTATUS prints the status of the Wlan.
|
||||
// The status of the Wlan "connection" can change if we have no relation
|
||||
// with the well known router anymore. Normally this relation is preserved
|
||||
// but sometimes we have to reconfirm to the router again and we get the same
|
||||
// address too.
|
||||
// So, if the router is still in range we can "survive" with the same address
|
||||
// and we may have to renew the "connection" from time to time.
|
||||
// But when we loose the SSID connection, we may have to look for another router.
|
||||
//
|
||||
// Parameters: <none>
|
||||
// Return value: Returns 1 when still WL_CONNETED, otherwise returns 0
|
||||
// ----------------------------------------------------------------------------
|
||||
int WlanStatus() {
|
||||
|
||||
switch (WiFi.status()) {
|
||||
case WL_CONNECTED:
|
||||
#if DUSB>=1
|
||||
if (debug>=0) {
|
||||
Serial.print(F("WlanCStatus:: CONNECTED to")); // 3
|
||||
Serial.println(WiFi.SSID());
|
||||
}
|
||||
#endif
|
||||
WiFi.setAutoReconnect(true); // Reconenct to this AP if DISCONNECTED
|
||||
return(1);
|
||||
break;
|
||||
|
||||
// In case we get disconnected from the AP we loose the IP address.
|
||||
// The ESP is configured to reconnect to the last router in memory.
|
||||
case WL_DISCONNECTED:
|
||||
#if DUSB>=1
|
||||
if (debug>=0) {
|
||||
Serial.print(F("WlanStatus:: DISCONNECTED, IP=")); // 6
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
#endif
|
||||
//while (! WiFi.isConnected() ) {
|
||||
// Wait
|
||||
delay(1);
|
||||
//}
|
||||
return(0);
|
||||
break;
|
||||
|
||||
// When still pocessing
|
||||
case WL_IDLE_STATUS:
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("WlanStatus:: IDLE")); // 0
|
||||
#endif
|
||||
break;
|
||||
|
||||
// This code is generated as soonas the AP is out of range
|
||||
// Whene detected, the program will search for a better AP in range
|
||||
case WL_NO_SSID_AVAIL:
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("WlanStatus:: NO SSID")); // 1
|
||||
#endif
|
||||
break;
|
||||
|
||||
case WL_CONNECT_FAILED:
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("WlanStatus:: FAILED")); // 4
|
||||
#endif
|
||||
break;
|
||||
|
||||
// Never seen this code
|
||||
case WL_SCAN_COMPLETED:
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("WlanStatus:: SCAN COMPLETE")); // 2
|
||||
#endif
|
||||
break;
|
||||
|
||||
// Never seen this code
|
||||
case WL_CONNECTION_LOST:
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("WlanStatus:: LOST")); // 5
|
||||
#endif
|
||||
break;
|
||||
|
||||
// This code is generated for example when WiFi.begin() has not been called
|
||||
// before accessing WiFi functions
|
||||
case WL_NO_SHIELD:
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("WlanStatus:: WL_NO_SHIELD")); //
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
#if DUSB>=1
|
||||
if (debug>=0) {
|
||||
Serial.print(F("WlanStatus:: code="));
|
||||
Serial.println(WiFi.status()); // 255 means ERROR
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// config.txt is a text file that contains lines(!) with WPA configuration items
|
||||
|
@ -63,13 +164,13 @@ int WlanReadWpa() {
|
|||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Print the WPA data of last WiFiManager to file
|
||||
// Print the WPA data of last WiFiManager to the config file
|
||||
// ----------------------------------------------------------------------------
|
||||
#if WIFIMANAGER==1
|
||||
int WlanWriteWpa( char* ssid, char *pass) {
|
||||
|
||||
#if DUSB>=1
|
||||
if ( debug >=0 ) && ( pdebug & P_MAIN )) {
|
||||
if (( debug >=0 ) && ( pdebug & P_MAIN )) {
|
||||
Serial.print(F("WlanWriteWpa:: ssid="));
|
||||
Serial.print(ssid);
|
||||
Serial.print(F(", pass="));
|
||||
|
@ -105,18 +206,22 @@ int WlanWriteWpa( char* ssid, char *pass) {
|
|||
// the reconnect is done first thing. By default the system will reconnect to the
|
||||
// samen SSID as it was connected to before.
|
||||
// Parameters:
|
||||
// int maxTry: Number of reties we do:
|
||||
// 0: Try forever. Which is normally what we want except for Setup maybe
|
||||
// int maxTry: Number of retries we do:
|
||||
// 0: Used during Setup first CONNECT
|
||||
// 1: Try once and if unsuccessful return(1);
|
||||
// x: Try x times
|
||||
//
|
||||
// Returns:
|
||||
// On failure: Return -1
|
||||
// int number of retries necessary
|
||||
// On connect: return 1
|
||||
// On Disconnect state: return 0
|
||||
//
|
||||
// XXX After a few retries, the ESP8266 should be reset. Note: Switching between
|
||||
// two SSID's does the trick. Rettrying the same SSID does not.
|
||||
// Workaround is found below: Let the ESP8266 forget the SSID
|
||||
// Workaround is found below: Let the ESP8266 forget the SSID
|
||||
//
|
||||
// NOTE: The Serial works only on debug setting and not on pdebug. This is
|
||||
// because WiFi problems would make webserver (which works on WiFI) useless.
|
||||
// ----------------------------------------------------------------------------
|
||||
int WlanConnect(int maxTry) {
|
||||
|
||||
|
@ -126,130 +231,98 @@ int WlanConnect(int maxTry) {
|
|||
|
||||
unsigned char agains = 0;
|
||||
unsigned char wpa_index = (WIFIMANAGER >0 ? 0 : 1); // Skip over first record for WiFiManager
|
||||
|
||||
// The initial setup() call is done with parameter 0
|
||||
// We clear the WiFi memory and start with previous AP.
|
||||
//
|
||||
if (maxTry==0) {
|
||||
Serial.println(F("WlanConnect:: Init para 0"));
|
||||
WiFi.persistent(false);
|
||||
WiFi.mode(WIFI_OFF); // this is a temporary line, to be removed after SDK update to 1.5.4
|
||||
if (gwayConfig.ssid.length() >0) {
|
||||
WiFi.begin(gwayConfig.ssid.c_str(), gwayConfig.pass.c_str());
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
// So try to connect to WLAN as long as we are not connected.
|
||||
// The try parameters tells us how many times we try before giving up
|
||||
// Value 0 is reserved for setup() first time connect
|
||||
int i=0;
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) return(1);
|
||||
|
||||
// We try 5 times before giving up on connect
|
||||
while ( (WiFi.status() != WL_CONNECTED) && ( i< maxTry ) )
|
||||
while ( (WiFi.status() != WL_CONNECTED) && ( i<= maxTry ) )
|
||||
{
|
||||
|
||||
// We try every SSID in wpa array until success
|
||||
for (int j=wpa_index; (j< (sizeof(wpa)/sizeof(wpa[0]))) && (WiFi.status() != WL_CONNECTED ); j++)
|
||||
{
|
||||
// Start with well-known access points in the list
|
||||
char *ssid = wpa[j].login;
|
||||
char *password = wpa[j].passw;
|
||||
// We try every SSID in wpa array until success
|
||||
for (int j=wpa_index; (j< (sizeof(wpa)/sizeof(wpa[0]))) && (WiFi.status() != WL_CONNECTED ); j++)
|
||||
{
|
||||
// Start with well-known access points in the list
|
||||
char *ssid = wpa[j].login;
|
||||
char *password = wpa[j].passw;
|
||||
#if DUSB>=1
|
||||
Serial.print(i);
|
||||
Serial.print(':');
|
||||
Serial.print(j);
|
||||
Serial.print(F(". WiFi connect SSID="));
|
||||
Serial.print(ssid);
|
||||
if (( debug>=1 ) && ( pdebug & P_MAIN )) {
|
||||
Serial.print(F(", pass="));
|
||||
Serial.print(password);
|
||||
}
|
||||
Serial.println();
|
||||
if (debug>=0) {
|
||||
Serial.print(i);
|
||||
Serial.print(':');
|
||||
Serial.print(j);
|
||||
Serial.print(F(". WiFi connect SSID="));
|
||||
Serial.print(ssid);
|
||||
if ( debug>=1 ) {
|
||||
Serial.print(F(", pass="));
|
||||
Serial.print(password);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
// Count the number of times we call WiFi.begin
|
||||
gwayConfig.wifis++;
|
||||
// Count the number of times we call WiFi.begin
|
||||
gwayConfig.wifis++;
|
||||
|
||||
//WiFi.disconnect();
|
||||
delay(1000);
|
||||
|
||||
WiFi.persistent(false);
|
||||
WiFi.mode(WIFI_OFF); // this is a temporary line, to be removed after SDK update to 1.5.4
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
delay(9000);
|
||||
|
||||
// We increase the time for connect but try the same SSID
|
||||
// We try for 10 times
|
||||
agains=1;
|
||||
while (((WiFi.status()) != WL_CONNECTED) && (agains < 10)) {
|
||||
agains++;
|
||||
delay(agains*500);
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN ))
|
||||
Serial.print(".");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check the connection status again
|
||||
switch (WiFi.status()) {
|
||||
case WL_CONNECTED:
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN ))
|
||||
Serial.println(F("WlanConnect:: CONNECTED")); // 3
|
||||
#endif
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
delay(1000);
|
||||
WiFi.begin(ssid, password);
|
||||
delay(8000);
|
||||
|
||||
// Check the connection status again, return values
|
||||
// 1 = CONNECTED
|
||||
// 0 = DISCONNECTED (will reconnect)
|
||||
// -1 = No SSID or other cause
|
||||
int stat = WlanStatus();
|
||||
if ( stat == 1) {
|
||||
writeGwayCfg(CONFIGFILE); // XXX Write cnfiguration to SPIFFS
|
||||
return(1);
|
||||
break;
|
||||
case WL_IDLE_STATUS:
|
||||
}
|
||||
|
||||
// We increase the time for connect but try the same SSID
|
||||
// We try for 10 times
|
||||
agains=1;
|
||||
while (((WiFi.status()) != WL_CONNECTED) && (agains < 10)) {
|
||||
agains++;
|
||||
delay(agains*500);
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN ))
|
||||
Serial.println(F("WlanConnect:: IDLE")); // 0
|
||||
#endif
|
||||
break;
|
||||
case WL_NO_SSID_AVAIL:
|
||||
#if DUSB>=1
|
||||
Serial.println(F("WlanConnect:: NO SSID")); // 1
|
||||
#endif
|
||||
break;
|
||||
case WL_CONNECT_FAILED:
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN ))
|
||||
Serial.println(F("WlanConnect:: FAILED")); // 4
|
||||
#endif
|
||||
break;
|
||||
case WL_DISCONNECTED:
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN ))
|
||||
Serial.println(F("WlanConnect:: DISCONNECTED")); // 6
|
||||
#endif
|
||||
break;
|
||||
case WL_SCAN_COMPLETED:
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN ))
|
||||
Serial.println(F("WlanConnect:: SCAN COMPLETE")); // 2
|
||||
#endif
|
||||
break;
|
||||
case WL_CONNECTION_LOST:
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN ))
|
||||
Serial.println(F("WlanConnect:: LOST")); // 5
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
#if DUSB>=1
|
||||
if (( debug>=0 ) && ( pdebug & P_MAIN )) {
|
||||
Serial.print(F("WlanConnect:: code="));
|
||||
Serial.println(WiFi.status());
|
||||
if ( debug>=0 ) {
|
||||
Serial.print(".");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( WiFi.status() == WL_DISCONNECTED) return(0); // wait
|
||||
|
||||
} //for
|
||||
i++; // Number of times we try to connect
|
||||
|
||||
// Make sure that we can connect to different AP's than 1
|
||||
// this is a patch. Normally we connect to previous one.
|
||||
WiFi.persistent(false);
|
||||
WiFi.mode(WIFI_OFF); // this is a temporary line, to be removed after SDK update to 1.5.4
|
||||
|
||||
} //for next WPA defined AP
|
||||
|
||||
i++; // Number of times we try to connect
|
||||
} //while
|
||||
|
||||
// It should not be possible to be here while WL_CONNECTed
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
#if DUSB>=1
|
||||
if (( debug>=3 ) && ( pdebug & P_MAIN )) {
|
||||
Serial.print(F("WLAN connected"));
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
writeGwayCfg(CONFIGFILE);
|
||||
return(1);
|
||||
}
|
||||
else {
|
||||
|
||||
// If we are not connected to a well known AP
|
||||
// we can invoike WIFIMANAGER or else return unsuccessful.
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
#if WIFIMANAGER==1
|
||||
#if DUSB>=1
|
||||
Serial.println(F("Starting Access Point Mode"));
|
||||
|
@ -273,7 +346,7 @@ int WlanConnect(int maxTry) {
|
|||
WlanWriteWpa((char *)sta_conf.ssid, (char *)sta_conf.password);
|
||||
#else
|
||||
#if DUSB>=1
|
||||
if (( debug>=0) && ( pdebug & P_MAIN )) {
|
||||
if (debug>=0) {
|
||||
Serial.println(F("WlanConnect:: Not connected after all"));
|
||||
Serial.print(F("WLAN retry="));
|
||||
Serial.print(i);
|
||||
|
@ -281,13 +354,11 @@ int WlanConnect(int maxTry) {
|
|||
Serial.print(WiFi.status() ); // Status. 3 is WL_CONNECTED
|
||||
Serial.println();
|
||||
}
|
||||
#endif // DUSB
|
||||
#endif// DUSB
|
||||
return(-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
yield();
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-03
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// Based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
@ -42,7 +42,7 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
|
|||
|
||||
int tries = 0;
|
||||
#if DUSB>=1
|
||||
Serial.print(F("readConfig:: Starting "));
|
||||
Serial.println(F("readConfig:: Starting "));
|
||||
#endif
|
||||
if (!SPIFFS.exists(fn)) {
|
||||
#if DUSB>=1
|
||||
|
@ -89,10 +89,10 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
|
|||
id_print(id, val);
|
||||
(*c).ssid = val; // val contains ssid, we do NO check
|
||||
}
|
||||
//else if (id == "PASS") { // WiFi Password
|
||||
// id_print(id, val);
|
||||
// (*c).pass = val;
|
||||
//}
|
||||
else if (id == "PASS") { // WiFi Password
|
||||
id_print(id, val);
|
||||
(*c).pass = val;
|
||||
}
|
||||
else if (id == "CH") { // Frequency Channel
|
||||
id_print(id,val);
|
||||
(*c).ch = (uint32_t) val.toInt();
|
||||
|
@ -195,7 +195,7 @@ int readConfig(const char *fn, struct espGwayConfig *c) {
|
|||
int writeGwayCfg(const char *fn) {
|
||||
|
||||
gwayConfig.ssid = WiFi.SSID();
|
||||
//gwayConfig.pass = WiFi.PASS(); // XXX We should find a way to store the password too
|
||||
gwayConfig.pass = WiFi.psk(); // XXX We should find a way to store the password too
|
||||
gwayConfig.ch = ifreq; // Frequency Index
|
||||
gwayConfig.sf = (uint8_t) sf; // Spreading Factor
|
||||
gwayConfig.debug = debug;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
@ -21,9 +21,19 @@
|
|||
#if OLED>=1
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Initilize the OLED functions.
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
void init_oLED()
|
||||
{
|
||||
#if defined OLED_RST
|
||||
pinMode(OLED_RST,OUTPUT);
|
||||
digitalWrite(OLED_RST, LOW); // low to reset OLED
|
||||
delay(50);
|
||||
digitalWrite(OLED_RST, HIGH); // must be high to turn on OLED
|
||||
delay(50);
|
||||
#endif
|
||||
// Initialising the UI will init the display too.
|
||||
display.init();
|
||||
display.flipScreenVertically();
|
||||
|
@ -33,26 +43,33 @@ void init_oLED()
|
|||
display.display();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Activate the OLED
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
void acti_oLED()
|
||||
{
|
||||
// Initialising the UI will init the display too.
|
||||
display.clear();
|
||||
|
||||
#if OLED==1
|
||||
display.setFont(ArialMT_Plain_24);
|
||||
display.drawString(0, 24, "READY");
|
||||
display.setFont(ArialMT_Plain_16);
|
||||
display.drawString(0, 16, "READY, SSID=");
|
||||
display.drawString(0, 32, WiFi.SSID());
|
||||
#elif OLED==2
|
||||
display.setFont(ArialMT_Plain_16);
|
||||
display.drawString(0, 24, "READY");
|
||||
display.drawString(0, 16, "READY, SSID=");
|
||||
display.drawString(0, 32, WiFi.SSID());
|
||||
#endif
|
||||
|
||||
display.display();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Print a message on the OLED.
|
||||
// Note: The whole message must fit in the buffer
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
void msg_oLED(String tim, String sf) {
|
||||
display.clear();
|
||||
display.setFont(ArialMT_Plain_16);
|
||||
|
@ -64,15 +81,14 @@ void msg_oLED(String tim, String sf) {
|
|||
yield();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Print the OLED address in use
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
void addr_oLED()
|
||||
{
|
||||
|
||||
Serial.print(F("OLED_ADDR=0x"));
|
||||
Serial.println(OLED_ADDR, HEX);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
//
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg
|
||||
// Verison 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Verison 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the MIT License
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg
|
||||
// Verison 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Verison 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the MIT License
|
||||
|
@ -16,27 +16,33 @@
|
|||
// Please specify the DevAddr and the AppSKey below (and on your LoRa backend).
|
||||
// Also you will have to choose what sensors to forward to your application.
|
||||
//
|
||||
// Note: disable sensors not used in ESP-sc-gway.h
|
||||
// - The GPS is included on TTGO T-Beam ESP32 boards by default.
|
||||
// - The battery sensor works by connecting the VCC pin to A0 analog port
|
||||
// ============================================================================
|
||||
|
||||
|
||||
#if GATEWAYNODE==1
|
||||
|
||||
#include "LoRaCode.h"
|
||||
|
||||
#if _GPS==1
|
||||
// Only used by GPS sensor code
|
||||
//
|
||||
static void smartDelay(unsigned long ms)
|
||||
{
|
||||
unsigned long start = millis();
|
||||
do
|
||||
{
|
||||
while (Serial1.available())
|
||||
gps.encode(Serial1.read());
|
||||
} while (millis() - start < ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
unsigned char DevAddr[4] = _DEVADDR ; // see ESP-sc-gway.h
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// XXX Experimental Read Internal Sensors
|
||||
//
|
||||
// You can monitor some settings of the RFM95/sx1276 chip. For example the temperature
|
||||
// which is set in REGTEMP in FSK mode (not in LORA). Or the battery value.
|
||||
// Find some sensible sensor values for LoRa radio and read them below in separate function
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//uint8_t readInternal(uint8_t reg) {
|
||||
//
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// LoRaSensors() is a function that puts sensor values in the MACPayload and
|
||||
// sends these values up to the server. For the server it is impossible to know
|
||||
|
@ -46,25 +52,79 @@ unsigned char DevAddr[4] = _DEVADDR ; // see ESP-sc-gway.h
|
|||
// of-course you can add any byte string you wish
|
||||
//
|
||||
// Parameters:
|
||||
// - buf: contains the buffer to put the sensor values in
|
||||
// - buf: contains the buffer to put the sensor values in (max==xx);
|
||||
// Returns:
|
||||
// - The amount of sensor characters put in the buffer
|
||||
// - The amount of sensor characters put in the buffer
|
||||
//
|
||||
// NOTE: The code in LoRaSensors() is provided as an example only.
|
||||
// The amount of sensor values as well as their message layout may differ
|
||||
// for each implementation.
|
||||
// Also, the message format used by this gateway is LoraCode, a message format
|
||||
// developed by me for sensor values. Each value is uniquely coded with an
|
||||
// id and a value, and the total message contains its length (less than 64 bytes)
|
||||
// and a parity value in byte[0] bit 7.
|
||||
// ----------------------------------------------------------------------------
|
||||
static int LoRaSensors(uint8_t *buf) {
|
||||
|
||||
uint8_t internalSersors;
|
||||
//internalSersors = readInternal(0x1A);
|
||||
//if (internalSersors > 0) {
|
||||
// return (internalSersors);
|
||||
//}
|
||||
|
||||
|
||||
uint8_t tchars = 1;
|
||||
buf[0] = 0x86; // 134; User code <lCode + len==3 + Parity
|
||||
buf[1] = 0x80; // 128; lCode code <battery>
|
||||
buf[2] = 0x3F; // 63; lCode code <value>
|
||||
// Parity = buf[0]==1 buf[1]=1 buf[2]=0 ==> even, so last bit of first byte must be 0
|
||||
|
||||
return(3); // return the number of bytes added to payload
|
||||
#if _BATTERY==1
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("LoRaSensors:: Battery"));
|
||||
#endif
|
||||
buf[tchars] = 0x80; // 128; lCode code <battery>
|
||||
buf[tchars+1] = 0x3F; // 63; lCode code <value>/30
|
||||
tchars+=2;
|
||||
#endif
|
||||
|
||||
#if _GPS==1
|
||||
#if DUSB>=1
|
||||
if (debug>=0)
|
||||
Serial.println(F("LoRaSensors:: GPS"));
|
||||
|
||||
if (debug>=1) {
|
||||
Serial.print("Latitude : ");
|
||||
Serial.println(gps.location.lat(), 5);
|
||||
Serial.print("Longitude : ");
|
||||
Serial.println(gps.location.lng(), 4);
|
||||
Serial.print("Satellites: ");
|
||||
Serial.println(gps.satellites.value());
|
||||
Serial.print("Altitude : ");
|
||||
Serial.print(gps.altitude.feet() / 3.2808);
|
||||
Serial.println("M");
|
||||
Serial.print("Time : ");
|
||||
Serial.print(gps.time.hour());
|
||||
Serial.print(":");
|
||||
Serial.print(gps.time.minute());
|
||||
Serial.print(":");
|
||||
Serial.println(gps.time.second());
|
||||
}
|
||||
#endif
|
||||
|
||||
smartDelay(1000);
|
||||
|
||||
if (millis() > 5000 && gps.charsProcessed() < 10) {
|
||||
#if DUSB>=1
|
||||
Serial.println(F("No GPS data received: check wiring"));
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
// Assuming we have a value, put it in the buf
|
||||
// The layout of thi message is specific to the user,
|
||||
// so adapt as needed.
|
||||
tchars += lcode.eGpsL(gps.location.lat(), gps.location.lng(), gps.altitude.value(),
|
||||
gps.satellites.value(), buf + tchars);
|
||||
|
||||
#endif
|
||||
|
||||
// If all sensor data is encoded, we encode the buffer
|
||||
|
||||
lcode.eMsg(buf, tchars); // Fill byte 0 with bytecount and Parity
|
||||
|
||||
return(tchars); // return the number of bytes added to payload
|
||||
}
|
||||
|
||||
|
||||
|
@ -395,7 +455,7 @@ static void checkMic(uint8_t *buf, uint8_t len, uint8_t *key) {
|
|||
// ( MHDR | ( FHDR | FPORT | FRMPAYLOAD ) | MIC )
|
||||
//
|
||||
// This function makes the totalpackage and calculates MIC
|
||||
// Te maximum size of the message is: 12 + ( 9 + 2 + 64 ) + 4
|
||||
// The maximum size of the message is: 12 + ( 9 + 2 + 64 ) + 4
|
||||
// So message size should be lass than 128 bytes if Payload is limited to 64 bytes.
|
||||
//
|
||||
// return value:
|
||||
|
@ -411,7 +471,7 @@ int sensorPacket() {
|
|||
struct LoraUp LUP;
|
||||
|
||||
// Init the other LoraUp fields
|
||||
LUP.sf = 9;
|
||||
LUP.sf = 8; // Send with SF8
|
||||
LUP.prssi = -50;
|
||||
LUP.rssicorr = 139;
|
||||
LUP.snr = 0;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
@ -157,7 +157,6 @@ void stateMachine()
|
|||
Serial.print(F("DONE :: "));
|
||||
SerialStat(intr);
|
||||
}
|
||||
|
||||
#endif
|
||||
eventTime=micros(); // reset the timer on timeout
|
||||
doneTime=micros(); // reset the timer on timeout
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-31
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by many people and making use of several libraries.
|
||||
//
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many other contributors.
|
||||
|
@ -58,9 +58,14 @@ long txDelay= 0x00; // tx delay time on top of server TMST
|
|||
// Frequencies
|
||||
// Set center frequency. If in doubt, choose the first one, comment all others
|
||||
// Each "real" gateway should support the first 3 frequencies according to LoRa spec.
|
||||
// NOTE: This means you have to specify at least 3 frequencies here for the single
|
||||
// channel gateway to work.
|
||||
|
||||
#if _LFREQ==868
|
||||
// This the the EU868 format as used in most of Europe
|
||||
// It is also the default for most of the single channel gateway work.
|
||||
int freqs [] = {
|
||||
868100000, // Channel 0, 868.1 MHz primary
|
||||
868100000, // Channel 0, 868.1 MHz/125 primary
|
||||
868300000, // Channel 1, 868.3 MHz mandatory
|
||||
868500000, // Channel 2, 868.5 MHz mandatory
|
||||
867100000, // Channel 3, 867.1 MHz Optional
|
||||
|
@ -68,10 +73,48 @@ int freqs [] = {
|
|||
867500000, // Channel 5, 867.5 MHz Optional
|
||||
867700000, // Channel 6, 867.7 MHz Optional
|
||||
867900000, // Channel 7, 867.9 MHz Optional
|
||||
868800000, // Channel 8, 868.9 MHz Optional
|
||||
869525000 // Channel 9, 869.5 MHz for responses gateway (10%)
|
||||
868800000, // Channel 8, 868.9 MHz/125 Optional
|
||||
869525000 // Channel 9, 869.5 MHz/125 for RX2 responses SF9(10%)
|
||||
// TTN defines an additional channel at 869.525Mhz using SF9 for class B. Not used
|
||||
};
|
||||
#elif _LFREQ==433
|
||||
// The following 3 frequencies should be defined/used in an EU433
|
||||
// environment.
|
||||
int freqs [] = {
|
||||
433175000, // Channel 0, 433.175 MHz/125 primary
|
||||
433375000, // Channel 1, 433.375 MHz primary
|
||||
433575000, // Channel 2, 433.575 MHz primary
|
||||
433775000, // Channel 3, 433.775 MHz primary
|
||||
433975000, // Channel 4, 433.975 MHz primary
|
||||
434175000, // Channel 5, 434.175 MHz primary
|
||||
434375000, // Channel 6, 434.375 MHz primary
|
||||
434575000, // Channel 7, 434.575 MHz primary
|
||||
434775000 // Channel 8, 434.775 MHz primary
|
||||
};
|
||||
#elif _LFREQ==915
|
||||
// US902=928
|
||||
// AU915-928
|
||||
int freqs [] = {
|
||||
// Uplink
|
||||
903900000, // Channel 0, SF7BW125 to SF10BW125 primary
|
||||
904100000, // Ch 1, SF7BW125 to SF10BW125
|
||||
904300000, // Ch 2, SF7BW125 to SF10BW125
|
||||
904500000, // Ch 3, SF7BW125 to SF10BW125
|
||||
904700000, // Ch 4, SF7BW125 to SF10BW125
|
||||
904900000, // Ch 5, SF7BW125 to SF10BW125
|
||||
905100000, // Ch 6, SF7BW125 to SF10BW125
|
||||
905100000, // Ch 7, SF7BW125 to SF10BW125
|
||||
904600000 // Ch 8, SF8BW500
|
||||
// Downlink
|
||||
// We should specify downlink frequencies here
|
||||
// SFxxxBW500
|
||||
};
|
||||
#else
|
||||
int freqs [] = {
|
||||
// Print an Error, Not supported
|
||||
#error "Sorry, but your frequency plan is not supported"
|
||||
};
|
||||
#endif
|
||||
uint32_t freq = freqs[0];
|
||||
uint8_t ifreq = 0; // Channel Index
|
||||
|
||||
|
@ -101,7 +144,7 @@ unsigned long detTime=0;
|
|||
|
||||
#if _PIN_OUT==1
|
||||
// ----------------------------------------------------------------------------
|
||||
// HALLARD Definition of the GPIO pins for Hallard type boards
|
||||
// Definition of the GPIO pins used by the Gateway for Hallard type boards
|
||||
//
|
||||
struct pins {
|
||||
uint8_t dio0=15; // GPIO15 / D8. For the Hallard board shared between DIO0/DIO1/DIO2
|
||||
|
@ -116,7 +159,7 @@ struct pins {
|
|||
|
||||
#elif _PIN_OUT==2
|
||||
// ----------------------------------------------------------------------------
|
||||
// COMRESULT gateway PCB use the following settings
|
||||
// For ComResult gateway PCB use the following settings
|
||||
struct pins {
|
||||
uint8_t dio0=5; // GPIO5 / D1. Dio0 used for one frequency and one SF
|
||||
uint8_t dio1=4; // GPIO4 / D2. Used for CAD, may or not be shared with DIO0
|
||||
|
@ -139,13 +182,13 @@ struct pins {
|
|||
uint8_t dio1=26; // GPIO26 / Used for CAD, may or not be shared with DIO0
|
||||
uint8_t dio2=26; // GPI2O6 / Used for frequency hopping, don't care
|
||||
uint8_t ss=18; // GPIO18 / Dx. Select pin connected to GPIO18
|
||||
uint8_t rst=14; // GPIO14 / D3. Reset pin not used
|
||||
uint8_t rst=14; // GPIO0 / D3. Reset pin not used
|
||||
} pins;
|
||||
|
||||
|
||||
#elif _PIN_OUT==4
|
||||
// ----------------------------------------------------------------------------
|
||||
// ESP32/TTGO based board
|
||||
// For ESP32/TTGO based board.
|
||||
// SCK == GPIO5/ PIN5
|
||||
// SS == GPIO18/PIN18 CS
|
||||
// MISO == GPIO19/ PIN19
|
||||
|
@ -153,21 +196,25 @@ struct pins {
|
|||
// RST == GPIO14/ PIN14
|
||||
struct pins {
|
||||
uint8_t dio0=26; // GPIO26 / Dio0 used for one frequency and one SF
|
||||
uint8_t dio1=33; // GPIO33 / Used for CAD, may or not be shared with DIO0
|
||||
uint8_t dio2=32; // GPIO32 / Used for frequency hopping, don't care
|
||||
uint8_t dio1=33; // GPIO26 / Used for CAD, may or not be shared with DIO0
|
||||
uint8_t dio2=32; // GPIO26 / Used for frequency hopping, don't care
|
||||
uint8_t ss=18; // GPIO18 / Dx. Select pin connected to GPIO18
|
||||
uint8_t rst=14; // GPIO14 / D3. Reset pin not used
|
||||
uint8_t rst=14; // GPIO0 / D3. Reset pin not used
|
||||
} pins;
|
||||
#define SCK 5
|
||||
#define MISO 19
|
||||
#define MOSI 27
|
||||
#define RST 14
|
||||
#define SS 18
|
||||
|
||||
#define GPS_RX 15
|
||||
#define GPS_TX 12
|
||||
|
||||
#elif _PIN_OUT==5
|
||||
// ----------------------------------------------------------------------------
|
||||
// ESP32/TTGO based board, with onboard battery and GPS(!)
|
||||
// For ESP32/TTGO based board for EU32 with 0.9" OLED
|
||||
// NOTE: This board shoudl be same as general type TTGO (nr 4)
|
||||
// but for the moment we include this as a separate item
|
||||
//
|
||||
// SCK == GPIO5/ PIN5
|
||||
// SS == GPIO18/PIN18 CS
|
||||
// MISO == GPIO19/ PIN19
|
||||
|
@ -175,15 +222,15 @@ struct pins {
|
|||
// RST == GPIO14/ PIN14
|
||||
struct pins {
|
||||
uint8_t dio0=26; // GPIO26 / Dio0 used for one frequency and one SF
|
||||
uint8_t dio1=33; // GPIO33 / Used for CAD, not be shared with DIO0, NOT CONNECTED BY DEFAULT
|
||||
uint8_t dio2=32; // GPIO32 / Used for frequency hopping, don't care
|
||||
uint8_t dio1=33; // GPIO26 / Used for CAD, may or not be shared with DIO0
|
||||
uint8_t dio2=32; // GPIO26 / Used for frequency hopping, don't care
|
||||
uint8_t ss=18; // GPIO18 / Dx. Select pin connected to GPIO18
|
||||
uint8_t rst=14; // GPIO14 / D3. Reset pin not used
|
||||
uint8_t rst=14; // GPIO0 / D3. Reset pin not used
|
||||
} pins;
|
||||
#define SCK 5
|
||||
#define MISO 19
|
||||
#define MOSI 27
|
||||
#define RST 14
|
||||
#define SCK 5 // Check
|
||||
#define MISO 19 // Check
|
||||
#define MOSI 27 // Check
|
||||
#define RST 14 // Check
|
||||
#define SS 18
|
||||
|
||||
#else
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 1-channel LoRa Gateway for ESP8266
|
||||
// Copyright (c) 2016, 2017, 2018 Maarten Westenberg version for ESP8266
|
||||
// Version 5.2.1
|
||||
// Date: 2018-06-06
|
||||
// Version 5.3.1
|
||||
// Date: 2018-06-30
|
||||
//
|
||||
// based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
|
||||
// and many others.
|
||||
|
@ -29,7 +29,7 @@
|
|||
#if OLED>=1 // If OLED is used
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Define the diffretn PIN's used for SCL/SDA for each arch.
|
||||
// Define the different PIN's used for SCL/SDA for each arch.
|
||||
//
|
||||
#if _PIN_OUT==1 // HALLARD
|
||||
#define OLED_SCL 5 // GPIO5 / D1
|
||||
|
@ -40,8 +40,9 @@
|
|||
#define OLED_SDA 2 // GPIO2 / D4
|
||||
|
||||
#elif _PIN_OUT==4 // TTGO (onboard version used, also for DIY)
|
||||
#define OLED_SCL 5 // GPIO5 / D1
|
||||
#define OLED_SDA 4 // GPIO4 / D2
|
||||
#define OLED_SCL 15 // GPIO15 /
|
||||
#define OLED_SDA 4 // GPIO4 /
|
||||
#define OLED_RST 16
|
||||
|
||||
#endif
|
||||
|
||||
|
|
10
README.md
10
README.md
|
@ -1,6 +1,6 @@
|
|||
# Single Channel LoRaWAN Gateway
|
||||
|
||||
Version 5.2.1, June 06, 2018
|
||||
Version 5.3.1, June 30, 2018
|
||||
Author: M. Westenberg (mw12554@hotmail.com)
|
||||
Copyright: M. Westenberg (mw12554@hotmail.com)
|
||||
|
||||
|
@ -15,18 +15,20 @@ Maintained by Maarten Westenberg (mw12554@hotmail.com)
|
|||
|
||||
# Description
|
||||
|
||||
First of all: PLEASE READ THIS FILE AND HTTP://THINGS4U.GITHUB.IO it should contain most of the information you need to get going.
|
||||
First of all: PLEASE READ THIS FILE AND HTTP://THINGS4U.GITHUB.IO it should contain most of the
|
||||
information you need to get going.
|
||||
Unfortunately I do not have the time to follow up on all emails, and as most information including pin-outs
|
||||
etc etc are contained on these pages I hope you have the time to read them before posting any questions.
|
||||
|
||||
I do have more than 10 Wemos D1 mini boards running, some I built myself,
|
||||
some 10+ on Hallard, 3 on ComResult and 2 ESP32 boards. They ALL work without problems.
|
||||
some 10+ on Hallard, 3 on ComResult and 4 ESP32 boards. They ALL work without problems
|
||||
on this code.
|
||||
I did find however that good soldering joints and wiring makes all the difference,
|
||||
so if you get resets you cannot explain, please have a second look at your wiring.
|
||||
|
||||
This repository contains a proof-of-concept implementation of a single channel LoRaWAN gateway for the ESP8266.
|
||||
Starting version 5.2 also the ESP32 of TTGO (and others) is supported.
|
||||
The software implements a standard LoRa gateway with the following exceptions on changes:
|
||||
The software implements a standard LoRa gateway with the following exceptions and changes:
|
||||
|
||||
- This LoRa gateway is not a full gateway but it implements just a one-channel/one frequency gateway.
|
||||
The minimum amount of frequencies supported by a full gateway is 3, most support 9 or more frequencies.
|
||||
|
|
|
@ -0,0 +1,581 @@
|
|||
// LoRa encoding and decoding functions
|
||||
// Copyright (c) 2016, 2017 Maarten Westenberg (mw12554@hotmail.com)
|
||||
// Version 1.2.0
|
||||
// Date: 2016-10-23
|
||||
// Version 1.2.0 on April 20, 2017
|
||||
//
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the MIT License
|
||||
// which accompanies this distribution, and is available at
|
||||
// https://opensource.org/licenses/mit-license.php
|
||||
//
|
||||
// Author: Maarten Westenberg
|
||||
//
|
||||
// The protocols used in this code:
|
||||
// 1. LoRA Specification version V1.0 and V1.1 for Gateway-Node communication
|
||||
//
|
||||
// 2. Semtech Basic communication protocol between Lora gateway and server version 3.0.0
|
||||
// https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT
|
||||
//
|
||||
// Notes:
|
||||
// The lCode specification is documented on a sparate page on github.
|
||||
//
|
||||
// Todo:
|
||||
// The luminescense is read as a 16-bit value in the library and converted to
|
||||
// a float value in order to get proper scaling etc. In the lCode lib it is
|
||||
// coded as a 2-byte value over the air, which might be incorrect for lux values
|
||||
// over 650 lux (which IS posible since bright daylight has more than 1000 lux).
|
||||
// So XXX we have to add another byte to cover values above 65
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if defined(__AVR__)
|
||||
#include <avr/pgmspace.h>
|
||||
#include <Arduino.h>
|
||||
#include <Battery.h>
|
||||
#elif defined(ARDUINO_ARCH_ESP8266) | defined(ESP32)
|
||||
#include <ESP.h>
|
||||
#elif defined(__MKL26Z64__)
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#error Unknown architecture in aes.cpp
|
||||
#endif
|
||||
|
||||
#include "LoRaCode.h"
|
||||
|
||||
int ldebug=DEBUG;
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Encode Temperature.
|
||||
// We use 2 bytes for temperature, first contains the integer partial_sort.
|
||||
// We add 100 so we effectively will measure temperatures between -100 and 154 degrees.
|
||||
// Second byte contains the fractional part in 2 decimals (00-99).
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eTemperature(float val, byte *msg) {
|
||||
int len=0;
|
||||
byte i= (byte) (val+100); // Integer part
|
||||
byte f= (byte) ( ((float)(val - (float)i -100)) * 100); // decimal part
|
||||
msg[len++] = ((byte)O_TEMP << 2) | 0x01; // Last 2 bits are 0x01, two bytes
|
||||
msg[len++] = i;
|
||||
msg[len++] = f;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Temperature "));
|
||||
Serial.print(i-100); // For readibility
|
||||
Serial.print(".");
|
||||
Serial.println(f);
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Code Humidity in the *msg
|
||||
// The humidity of the sensor is between 0-100%, we encode this value * 2 so that
|
||||
// byte value is betwene 0 and 199.
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eHumidity(float val, byte *msg) {
|
||||
int len=0;
|
||||
byte i = (byte) ((float)val *2); // Value times 2
|
||||
msg[len++] = ((byte)O_HUMI << 2) | 0x00; // Last 2 bits are 0x00, one byte
|
||||
msg[len++] = i; //
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Humidity "));
|
||||
Serial.println((float)(i/2)); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Code the Airpressure.
|
||||
// The coded value is the measured value minus 900. This gives an airpressure
|
||||
// range from 850-1104
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eAirpressure(float val, byte *msg) {
|
||||
int len=0;
|
||||
byte i = (byte) ((float)val -850); // Value times 2
|
||||
msg[len++] = ((byte)O_AIRP << 2) | 0x00; // Last 2 bits are 0x00, one byte
|
||||
msg[len++] = i; //
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Airpressure "));
|
||||
Serial.println((float)(i + 850)); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// GPS lat and lng encoding
|
||||
// There are several ways to encode GPS data. Eother by mapping on 3 or 4 bytes of
|
||||
// Floating, or by just multiplying with 1,000,000 for example (gives 6 digits
|
||||
// precision which is enough for almost all applications)
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eGps(double lat, double lng, byte *msg) {
|
||||
#if DEBUG>0
|
||||
if (ldebug>=1) {
|
||||
Serial.print(F(" LAT: ")); Serial.print(lat,6);
|
||||
Serial.print(F(" LNG: ")); Serial.println(lng,6);
|
||||
}
|
||||
#endif
|
||||
int len=0;
|
||||
long factor = 1000000;
|
||||
msg[len++] = ((byte)O_GPS << 2) | 0x00; // Last 2 bits are 0x00, don't care
|
||||
const long calculatedLat = (long)(lat * factor);
|
||||
msg[len++] = (calculatedLat >> (8*3)) & 0xFF;
|
||||
msg[len++] = (calculatedLat >> (8*2)) & 0xFF;
|
||||
msg[len++] = (calculatedLat >> (8*1)) & 0xFF;
|
||||
msg[len++] = (calculatedLat >> (8*0)) & 0xFF;
|
||||
const long calculatedLng = (long)(lng * factor);
|
||||
msg[len++] = (calculatedLng >> (8*3)) & 0xFF;
|
||||
msg[len++] = (calculatedLng >> (8*2)) & 0xFF;
|
||||
msg[len++] = (calculatedLng >> (8*1)) & 0xFF;
|
||||
msg[len++] = (calculatedLng >> (8*0)) & 0xFF;
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Code the extended GPS format
|
||||
// latitude and longitude are coded just like the short format
|
||||
// Altitude is a long containing the altitude in cm
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eGpsL(double lat, double lng, long alt, int sat,
|
||||
byte *msg) {
|
||||
if (ldebug>=1) {
|
||||
Serial.print(F(" LAT: ")); Serial.print(lat,6);
|
||||
Serial.print(F(" LNG: ")); Serial.print(lng,6);
|
||||
Serial.print(F(" ALT: ")); Serial.print(alt/100);
|
||||
Serial.print(F(" SAT: ")); Serial.println(sat);
|
||||
}
|
||||
int len=0;
|
||||
long factor = 1000000;
|
||||
msg[len++] = ((byte)O_GPSL << 2) | 0x00; // Last 2 bits are 0x00, don't care
|
||||
const long calculatedLat = (long)(lat * factor);
|
||||
msg[len++] = (calculatedLat >> (8*3)) & 0xFF;
|
||||
msg[len++] = (calculatedLat >> (8*2)) & 0xFF;
|
||||
msg[len++] = (calculatedLat >> (8*1)) & 0xFF;
|
||||
msg[len++] = (calculatedLat >> (8*0)) & 0xFF;
|
||||
const long calculatedLng = (long)(lng * factor);
|
||||
msg[len++] = (calculatedLng >> (8*3)) & 0xFF;
|
||||
msg[len++] = (calculatedLng >> (8*2)) & 0xFF;
|
||||
msg[len++] = (calculatedLng >> (8*1)) & 0xFF;
|
||||
msg[len++] = (calculatedLng >> (8*0)) & 0xFF;
|
||||
const long calculatedAlt = (long)(alt); // Altitude is integer specified in cm (converted later to m)
|
||||
msg[len++] = (calculatedAlt >> (8*3)) & 0xFF;
|
||||
msg[len++] = (calculatedAlt >> (8*2)) & 0xFF;
|
||||
msg[len++] = (calculatedAlt >> (8*1)) & 0xFF;
|
||||
msg[len++] = (calculatedAlt >> (8*0)) & 0xFF;
|
||||
msg[len++] = sat & 0xFF; // Positive number, assumed always to be less than 255
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Encode the 1-bit PIR value
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::ePir(int val, byte *msg) {
|
||||
int i = (byte) ( val );
|
||||
int len=0; //
|
||||
msg[len++] = (O_PIR << 2) | 0x00; // Last 2 bits are 0x00, one byte
|
||||
msg[len++] = i;
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Encode Airquality Value.
|
||||
// Airquality through SDS011 sensors is measured with two float values
|
||||
// and read as a 10-bit value (0-1024). We use a 2 x 2-byte value
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eAirquality(int pm25, int pm10, byte *msg) {
|
||||
int len=0;
|
||||
|
||||
uint16_t val = (uint16_t) (pm25);
|
||||
msg[len++] = (O_AQ << 2) | 0x03; // Last 2 bits are 0x03, so 4 bytes data
|
||||
msg[len++] = (val >> 8) & 0xFF;
|
||||
msg[len++] = val & 0xFF;
|
||||
|
||||
val = (uint16_t) (pm10);
|
||||
msg[len++] = (val >> 8) & 0xFF;
|
||||
msg[len++] = val & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Airquality <"));
|
||||
Serial.print(len);
|
||||
Serial.print(F("> "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Encode a Multi-Button sensor. This sensor is a concentrator that receives
|
||||
// several sensor values over 433MHz and retransmits them over LoRa
|
||||
// The LoRa sensor node contains the main address (LoRa id), the concentrated
|
||||
// sendors have their own unique address/channel combination.
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eMbuttons(byte val, unsigned long address, unsigned short channel, byte *msg) {
|
||||
int len=0;
|
||||
msg[len++] = (O_MB << 2) | 0x00; // Several bytes, do not care
|
||||
|
||||
msg[len++] = val; // First code the value
|
||||
|
||||
msg[len++] = (address >> (8*3)) & 0xFF; // Address
|
||||
msg[len++] = (address >> (8*2)) & 0xFF;
|
||||
msg[len++] = (address >> (8*1)) & 0xFF;
|
||||
msg[len++] = (address >> (8*0)) & 0xFF;
|
||||
|
||||
msg[len++] = (channel >> (8*1)) & 0xFF; // Channel
|
||||
msg[len++] = (channel >> (8*0)) & 0xFF;
|
||||
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Multi-Button "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Moisture detection with two metal sensors in fluid or soil
|
||||
//
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eMoist(int val, byte *msg) {
|
||||
int len=0;
|
||||
msg[len++] = (O_MOIST << 2) | 0x00; // Last 2 bits are 0x00, 1 byte
|
||||
msg[len++] = (val / 4 ) & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Moisture "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Luminescense detection with two metal sensors in fluid or soil
|
||||
// The value to be decoded is 2-byte value which gives
|
||||
// an integer resolution from 0 to 65535
|
||||
// It is possible to add a third byte for extra resolution (2 decimals).
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eLuminescense(float val, byte *msg) {
|
||||
int len=0;
|
||||
uint16_t lux = (uint16_t) (val);
|
||||
// now determine the fraction for a third byte
|
||||
msg[len++] = (O_LUMI << 2) | 0x01; // Last 2 bits are 0x00, 2 bytes resolution
|
||||
msg[len++] = (lux >> (8*1)) & 0xFF; // LSB
|
||||
msg[len++] = (lux >> (8*0)) & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Lumi "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
int LoRaCode::eLuminescenseL(float val, byte *msg) {
|
||||
int len=0;
|
||||
uint16_t lux = (uint16_t) (val);
|
||||
// now determine the fraction for a third byte
|
||||
uint8_t frac = (uint8_t) ((val-lux) * 100);
|
||||
|
||||
msg[len++] = (O_LUMI << 2) | 0x02; // Last 2 bits are 0x00, 3 bytes resolution
|
||||
msg[len++] = (lux >> (8*1)) & 0xFF; // LSB
|
||||
msg[len++] = (lux >> (8*0)) & 0xFF;
|
||||
msg[len++] = (frac) & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Lumi L="));
|
||||
Serial.print(lux); // For readibility
|
||||
Serial.print('.');
|
||||
Serial.println(frac); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Distance detection
|
||||
// In this case we use 2 bytes for 0-65535 mm (which is more than we need)
|
||||
// NOTE: The sensor will report in mm resolution, but the server side
|
||||
// will decode in cm resolution with one decimal fraction (if available)
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eDistance(int val, byte *msg) {
|
||||
int len=0;
|
||||
msg[len++] = (O_DIST << 2) | 0x01; // Last 2 bits are 0x00, 2 bytes resolution
|
||||
msg[len++] = (val >> (8*1)) & 0xFF; // LSB
|
||||
msg[len++] = (val >> (8*0)) & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Dist "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Encode Gas concentration Value.
|
||||
// Airquality through MQxx or AQxx sensors is measured through the Analog port
|
||||
// and read as a 10-bit value (0-1024). We use a 2-byte value
|
||||
// In order to tell the server which sensor is reporting (we can have several)
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eGas(int val, byte *msg) {
|
||||
int len=0;
|
||||
msg[len++] = (O_GAS << 2) | 0x01; // Last 2 bits are 0x01, 2 bytes
|
||||
msg[len++] = (val >> 8) & 0xFF;
|
||||
msg[len++] = val & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Gas "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Encode Battery Value.
|
||||
// Battery Voltage is between 2 and 4 Volts (sometimes 12V)
|
||||
// We therefore multiply by 20, reported values are between 1 and 255, so
|
||||
// sensor values between 0,05 and 12.75 Volts
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eBattery(float val, byte *msg) {
|
||||
int len=0;
|
||||
int i = (byte) ((float)val *20); // Value times 20
|
||||
msg[len++] = (O_BATT << 2) | 0x00; // Last 2 bits are 0x00, one byte
|
||||
msg[len++] = i;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Battery "));
|
||||
Serial.println((float)(i/20)); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Encode AD Converter value for pin adc0 and adv1
|
||||
// Battery Voltage is between 2 and 4 Volts (sometimes 12V)
|
||||
// We therefore multiply by 20, reported values are between 1 and 255, so
|
||||
// sensor values between 0,05 and 12.75 Volts
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eAdc0(int val, byte *msg) {
|
||||
int len=0;
|
||||
msg[len++] = (O_ADC0 << 2) | 0x00; // Last 2 bits are 0x00, 1 byte
|
||||
msg[len++] = (val / 4 ) & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Adc0 "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
int LoRaCode::eAdc1(int val, byte *msg) {
|
||||
int len=0;
|
||||
msg[len++] = (O_ADC1 << 2) | 0x00; // Last 2 bits are 0x00, 1 byte
|
||||
msg[len++] = (val / 4 ) & 0xFF;
|
||||
#if DEBUG>0
|
||||
if (ldebug >=1) {
|
||||
Serial.print(F("lcode:: Add Adc1 "));
|
||||
Serial.println(val); // For readibility
|
||||
}
|
||||
#endif
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Function to encode the sensor values to the Payload message
|
||||
// Input: Opcode and Value
|
||||
// Output: msg
|
||||
// return: Number of bytes added to msg
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::eVal (int opcode, byte *val, byte *msg) {
|
||||
int len=0;
|
||||
switch (opcode) {
|
||||
case O_TEMP: // Temperature
|
||||
len += eTemperature((float) *val, msg);
|
||||
break;
|
||||
case O_HUMI: // Humidity
|
||||
len += eHumidity((float) *val, msg);
|
||||
break;
|
||||
case O_AIRP: // Airpressure
|
||||
len += eAirpressure((float) *val, msg);
|
||||
break;
|
||||
case O_GPS: // GPS short Info
|
||||
//len += eGps(lat, lng, msg);
|
||||
break;
|
||||
case O_PIR: // PIR
|
||||
len += ePir((int) *val, msg);
|
||||
break;
|
||||
|
||||
case O_MOIST: // Moisture
|
||||
len += eMoist((int) *val, msg);
|
||||
break;
|
||||
case O_LUMI: // Luminescense
|
||||
len += eLuminescense((int) *val, msg);
|
||||
break;
|
||||
case O_BATT: // Battery
|
||||
len += eBattery((float) *val, msg);
|
||||
break;
|
||||
default:
|
||||
#if DEBUG>0
|
||||
Serial.println("lCode:: Error opcode not known");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return(len);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Function to encode the Payload message (final step)
|
||||
// This function will modify the first byte of the string to encode the length
|
||||
// and the parity. Payload begins at position 1, byte 0 is reserved
|
||||
// --------------------------------------------------------------------------------
|
||||
bool LoRaCode::eMsg (byte * msg, int len) {
|
||||
unsigned char par = 0;
|
||||
if (len > 64) {
|
||||
#if DEBUG>0
|
||||
Serial.println("lCodeMsg:: Error, string to long");
|
||||
#endif
|
||||
return(false);
|
||||
}
|
||||
#if DEBUG>0
|
||||
if (ldebug>=1) {Serial.print(F("LCodeMsg:: <")); Serial.print(len); Serial.print(F("> ")); }
|
||||
#endif
|
||||
// else we probably have a good message
|
||||
msg[0] = ( len << 1 ) | (0x80);
|
||||
|
||||
// Now we have to calculate the Parity for the message
|
||||
for (int i=0; i< len; i++) {
|
||||
byte cc = msg[i];
|
||||
par ^= cc;
|
||||
}
|
||||
|
||||
// Now we have par as one byte and need to XOR the bits of that byte.
|
||||
unsigned char pp = 8; // width of byte in #bits
|
||||
while (pp > 1) {
|
||||
par ^= par >> (pp/2);
|
||||
pp -= pp/2;
|
||||
}
|
||||
|
||||
if (par & 0x01) { // if odd number of 1's in string
|
||||
#if DEBUG>0
|
||||
if (ldebug>=1) Serial.print(F(" odd "));
|
||||
#endif
|
||||
msg[0] |= 0x01; // Add another 1 to make parity even
|
||||
}
|
||||
else {
|
||||
#if DEBUG>0
|
||||
if (ldebug>=1) Serial.print(F(" even "));
|
||||
#endif
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Print an encoded string
|
||||
// --------------------------------------------------------------------------------
|
||||
void LoRaCode::lPrint (byte *msg, int len) {
|
||||
Serial.print(F("lCode: "));
|
||||
for (int i=0; i< len; i++) {
|
||||
if (msg[i]<10) Serial.print('0');
|
||||
Serial.print(msg[i],HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Decode first byte of message containing length
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::dLen (byte *msg) {
|
||||
if ( ! (msg[0] & 0x80 )) return(-1); // Error
|
||||
int len = msg[0] & 0x7F; // Blank out first bit which is always 1 with LoRaCode
|
||||
return (len >> 1);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Decode message. One function for all, always returns a float
|
||||
// We expect that the buffer is large enough and will contain all bytes required
|
||||
// by that specific encoding
|
||||
// XXX This function needs finishig (never used at the moment)
|
||||
// PARAMETERS:
|
||||
// msg: Contains the message as a byte string
|
||||
// val: contains the decoded value as a float (xxx)
|
||||
// mode: Contains the opcode of the decoded command
|
||||
// RETURN:
|
||||
// The number of bytes read from the buffer
|
||||
// --------------------------------------------------------------------------------
|
||||
int LoRaCode::dMsg (byte *msg, byte *val, byte *mode) {
|
||||
float res;
|
||||
byte len = msg[0] & 0x03; // Last 2 bits
|
||||
*mode = (byte) (msg[0] >> 2);
|
||||
switch (*mode) {
|
||||
case O_TEMP:
|
||||
*val = (float) msg[1]- 100 + ( (float) msg[2] / 100);
|
||||
return(3);
|
||||
break;
|
||||
case O_HUMI:
|
||||
*val = (float) msg[1] / 2;
|
||||
return(2);
|
||||
break;
|
||||
case O_AIRP:
|
||||
*val = 0;
|
||||
return(2);
|
||||
break;
|
||||
case O_GPS: // Returning one float does not work for GPS. function never used
|
||||
*val = 0;
|
||||
return(9);
|
||||
break;
|
||||
case O_GPSL:
|
||||
*val = 0;
|
||||
return(14);
|
||||
break;
|
||||
case O_PIR:
|
||||
*val = msg[1];
|
||||
return(2);
|
||||
break;
|
||||
case O_AQ:
|
||||
*val = 0;
|
||||
return(3);
|
||||
break;
|
||||
case O_BATT:
|
||||
*val = (float) msg[1] / 20;
|
||||
return(2);
|
||||
break;
|
||||
case O_STAT:
|
||||
*val = 0;
|
||||
return(1);
|
||||
case O_1CH:
|
||||
*val = msg[1];
|
||||
return(2);
|
||||
break;
|
||||
case O_SF:
|
||||
*val = msg[1];
|
||||
return(2);
|
||||
break;
|
||||
case O_TIM: // Timing of the wait cyclus
|
||||
val[0] = msg[1];
|
||||
val[1] = msg[2];
|
||||
return(3); // total lengt 2 bytes data + 1 byte opcode
|
||||
break;
|
||||
default:
|
||||
return(0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Variable declaration
|
||||
LoRaCode lcode;
|
|
@ -0,0 +1,103 @@
|
|||
// LoRa encoding and decoding functions
|
||||
// Copyright (c) 2016 Maarten Westenberg
|
||||
// Version 1.1.0
|
||||
// Date: 2016-10-23
|
||||
//
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the MIT License
|
||||
// which accompanies this distribution, and is available at
|
||||
// https://opensource.org/licenses/mit-license.php
|
||||
//
|
||||
// Author: Maarten Westenberg
|
||||
//
|
||||
// The protocols used in this code:
|
||||
// 1. LoRA Specification version V1.0 and V1.1 for Gateway-Node communication
|
||||
//
|
||||
// 2. Semtech Basic communication protocol between Lora gateway and server version 3.0.0
|
||||
// https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT
|
||||
//
|
||||
// Notes:
|
||||
// The lCode specification is documented on a sparate page on github.
|
||||
//
|
||||
// Todo:
|
||||
// The luminescense is read as a 16-bit value in the library and converted to
|
||||
// a float value in order to get proper scaling etc. In the lCode lib it is
|
||||
// coded as a 2-byte value over the air, which might be incorrect for lux values
|
||||
// over 650 lux (which IS posible since bright daylight has more than 1000 lux).
|
||||
// So XXX we have to add another byte to cover values above 65
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef LoRaCode_h
|
||||
#define LoRaCode_h
|
||||
|
||||
// Op Codes
|
||||
#define O_TEMP 0x01 // Temperature is a one-byte code
|
||||
#define O_HUMI 0x02 // Humidity is a one-byte code
|
||||
#define O_AIRP 0x03 // Air pressure is a one-byte code
|
||||
#define O_GPS 0x04 // Short version: ONLY 3 bytes LAT and 3 bytes LONG
|
||||
#define O_GPSL 0x05 // Long GPS
|
||||
#define O_PIR 0x06 // Movement, 1 bit (=1 byte)
|
||||
#define O_AQ 0x07 // Airquality
|
||||
#define O_RTC 0x08 // Real Time Clock
|
||||
#define O_COMPASS 0x09 // Compass
|
||||
#define O_MB 0x0A // Multi Sensors 433
|
||||
#define O_MOIST 0x0B // Moisture is one-byte
|
||||
#define O_LUMI 0x0C // Luminescense u16
|
||||
#define O_DIST 0x0D // Distance is 2-byte
|
||||
#define O_GAS 0x0E // GAS
|
||||
// 0x0F
|
||||
|
||||
// 0x10 // 16 values
|
||||
// 0x11
|
||||
// ..
|
||||
// 0x1F
|
||||
|
||||
#define O_BATT 0x20 // Internal Battery
|
||||
#define O_ADC0 0x21 // AD converter on pin 0
|
||||
#define O_ADC1 0x22
|
||||
|
||||
// Reserved for LoRa messages (especially downstream)
|
||||
#define O_STAT 0x30 // Ask for status message from node
|
||||
#define O_SF 0x31 // Spreading factor change OFF=0, values 7-12
|
||||
#define O_TIM 0x32 // Timing of the wait cyclus (20 to 7200 seconds)
|
||||
#define O_1CH 0x33 // Single channel: Channel Value=0-9, OFF==255
|
||||
#define O_LOC 0x34 // Ask for the location. Responds with GPS (if available)
|
||||
|
||||
// ..
|
||||
// 0x3F
|
||||
|
||||
class LoRaCode
|
||||
{
|
||||
public:
|
||||
|
||||
int eVal(int opcode, byte *val, byte *msg);
|
||||
int eTemperature(float val, byte *msg);
|
||||
int eHumidity(float val, byte *msg);
|
||||
int eAirpressure(float val, byte *msg);
|
||||
int eGps(double lat, double lng, byte *msg);
|
||||
int eGpsL(double lat, double lng, long alt, int sat, byte *msg);
|
||||
int ePir(int val, byte *msg);
|
||||
int eAirquality(int pm25, int pm10, byte *msg); // value 0 (good) -1024 (gas)
|
||||
int eMbuttons(byte val, unsigned long address, unsigned short channel, byte *msg); // concentrator for multi-buttons
|
||||
int eMoist(int val, byte *msg); // 255 is dry, 0 is wet
|
||||
int eLuminescense(float val, byte *msg); // val contains light intensity
|
||||
int eLuminescenseL(float val, byte *msg); // long contains light intensity
|
||||
int eDistance(int val, byte *msg);
|
||||
int eGas(int val, byte *msg);
|
||||
|
||||
// opcodes 0x0F until 0x1F
|
||||
int eBattery(float val, byte *msg);
|
||||
int eAdc0(int val, byte *msg); // Pin A0 has 1024 values, we use 256
|
||||
int eAdc1(int val, byte *msg); // Pin A1 has 1024 values, we use 256
|
||||
|
||||
bool eMsg(byte *msg, int len);
|
||||
void lPrint(byte *msg, int len);
|
||||
|
||||
//Decoding (downstream)
|
||||
int dLen (byte *msg);
|
||||
int dMsg (byte *msg, byte *val, byte *mode);
|
||||
|
||||
};
|
||||
|
||||
extern LoRaCode lcode;
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
[.ShellClassInfo]
|
||||
InfoTip=Deze map wordt online gedeeld.
|
||||
IconFile=C:\Program Files\Google\Drive\googledrivesync.exe
|
||||
IconIndex=16
|
||||
|
Ładowanie…
Reference in New Issue