Add support for GPS as NTP server

Add support for GPS as NTP server by Christian Baars and Adrian Scillato
This commit is contained in:
Theo Arends 2019-12-23 15:39:07 +01:00
parent d5dcf462d0
commit fb8bb1223a
6 changed files with 216 additions and 194 deletions

View File

@ -54,5 +54,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
- Change Smoother ``Fade`` using 100Hz instead of 20Hz animation (#7179) - Change Smoother ``Fade`` using 100Hz instead of 20Hz animation (#7179)
- Change number of rule ``Var``s and ``Mem``s from 5 to 16 (#4933) - Change number of rule ``Var``s and ``Mem``s from 5 to 16 (#4933)
- Add support for max 150 characters in most command parameter strings (#3686, #4754) - Add support for max 150 characters in most command parameter strings (#3686, #4754)
- Add support for GPS as NTP server by Christian Baars and Adrian Scillato
- Add Zigbee coalesce sensor attributes into a single message - Add Zigbee coalesce sensor attributes into a single message
- Add Deepsleep start delay based on Teleperiod if ``Teleperiod`` differs from 10 or 300 - Add Deepsleep start delay based on Teleperiod if ``Teleperiod`` differs from 10 or 300

View File

@ -6,6 +6,7 @@
- Change Smoother ``Fade`` using 100Hz instead of 20Hz animation (#7179) - Change Smoother ``Fade`` using 100Hz instead of 20Hz animation (#7179)
- Change number of rule ``Var``s and ``Mem``s from 5 to 16 (#4933) - Change number of rule ``Var``s and ``Mem``s from 5 to 16 (#4933)
- Add support for max 150 characters in most command parameter strings (#3686, #4754) - Add support for max 150 characters in most command parameter strings (#3686, #4754)
- Add support for GPS as NTP server by Christian Baars and Adrian Scillato
- Add Zigbee coalesce sensor attributes into a single message - Add Zigbee coalesce sensor attributes into a single message
- Add Deepsleep start delay based on Teleperiod if ``Teleperiod`` differs from 10 or 300 - Add Deepsleep start delay based on Teleperiod if ``Teleperiod`` differs from 10 or 300

View File

@ -493,7 +493,9 @@ void GetFeatures(void)
feature5 |= 0x00100000; feature5 |= 0x00100000;
#endif #endif
// feature5 |= 0x00200000; // feature5 |= 0x00200000;
// feature5 |= 0x00400000; #ifdef USE_GPS
feature5 |= 0x00400000;
#endif
// feature5 |= 0x00800000; // feature5 |= 0x00800000;
// feature5 |= 0x01000000; // feature5 |= 0x01000000;

View File

@ -295,7 +295,8 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|" D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|" D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|"
D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "i|" D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "i|"
D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|" D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|"
D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX
; ;
const char kSensorNamesFixed[] PROGMEM = const char kSensorNamesFixed[] PROGMEM =
@ -673,6 +674,7 @@ const uint8_t kGpioNiceList[] PROGMEM = {
#endif // USE_SOLAX_X1 #endif // USE_SOLAX_X1
#endif // USE_ENERGY_SENSOR #endif // USE_ENERGY_SENSOR
// Serial
#ifdef USE_SERIAL_BRIDGE #ifdef USE_SERIAL_BRIDGE
GPIO_SBR_TX, // Serial Bridge Serial interface GPIO_SBR_TX, // Serial Bridge Serial interface
GPIO_SBR_RX, // Serial Bridge Serial interface GPIO_SBR_RX, // Serial Bridge Serial interface
@ -727,6 +729,11 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_IBEACON_RX, GPIO_IBEACON_RX,
GPIO_IBEACON_TX, GPIO_IBEACON_TX,
#endif #endif
#ifdef USE_GPS
GPIO_GPS_RX, // GPS serial interface
GPIO_GPS_TX, // GPS serial interface
#endif
#ifdef USE_MGC3130 #ifdef USE_MGC3130
GPIO_MGC3130_XFER, GPIO_MGC3130_XFER,
GPIO_MGC3130_RESET, GPIO_MGC3130_RESET,
@ -756,11 +763,7 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_A4988_MS3, // A4988 microstep pin3 GPIO_A4988_MS3, // A4988 microstep pin3
#endif #endif
#ifdef USE_DEEPSLEEP #ifdef USE_DEEPSLEEP
GPIO_DEEPSLEEP GPIO_DEEPSLEEP,
#endif
#ifdef USE_GPS
GPIO_GPS_RX, // GPS serial interface
GPIO_GPS_TX // GPS serial interface
#endif #endif
}; };

View File

@ -1,5 +1,5 @@
/* /*
xsns_60_GPS.ino - GPS UBLOX support for Sonoff-Tasmota xsns_60_GPS.ino - GPS UBLOX support for Tasmota
Copyright (C) 2019 Theo Arends, Christian Baars and Adrian Scillato Copyright (C) 2019 Theo Arends, Christian Baars and Adrian Scillato
@ -15,7 +15,10 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_GPS
/*********************************************************************************************\
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
Version Date Action Description Version Date Action Description
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
@ -97,14 +100,13 @@ rule2 on tele-GPS#int>9 do DisplayText [f0c9l4]I%value% endon on tele-GPS#int
rule3 on tele-FLOG#sec do DisplayText [f0c1l4]SAV:%value% endon on tele-FLOG#rec==1 do DisplayText [f0c1l4]REC: endon on tele-FLOG#mode do DisplayText [f0c14l4]M%value% endon rule3 on tele-FLOG#sec do DisplayText [f0c1l4]SAV:%value% endon on tele-FLOG#rec==1 do DisplayText [f0c1l4]REC: endon on tele-FLOG#mode do DisplayText [f0c14l4]M%value% endon
*/ \*********************************************************************************************/
#ifdef USE_GPS #define XSNS_60 60
#include "NTPServer.h" #include "NTPServer.h"
#include "NTPPacket.h" #include "NTPPacket.h"
/*********************************************************************************************\ /*********************************************************************************************\
* constants * constants
\*********************************************************************************************/ \*********************************************************************************************/
@ -117,7 +119,6 @@ const char kUBXTypes[] PROGMEM = "UBX";
#define UBX_LAT_LON_THRESHOLD 1000 // filter out some noise of local drift #define UBX_LAT_LON_THRESHOLD 1000 // filter out some noise of local drift
/********************************************************************************************\ /********************************************************************************************\
| *globals | *globals
\*********************************************************************************************/ \*********************************************************************************************/
@ -281,7 +282,9 @@ NtpServer timeServer(PortUdp);
/*********************************************************************************************\ /*********************************************************************************************\
* helper function * helper function
\*********************************************************************************************/ \*********************************************************************************************/
void UBXcalcChecksum(char* CK, size_t msgSize) {
void UBXcalcChecksum(char* CK, size_t msgSize)
{
memset(CK, 0, 2); memset(CK, 0, 2);
for (int i = 0; i < msgSize; i++) { for (int i = 0; i < msgSize; i++) {
CK[0] += ((char*)(&UBX.Message))[i]; CK[0] += ((char*)(&UBX.Message))[i];
@ -289,19 +292,22 @@ void UBXcalcChecksum(char* CK, size_t msgSize) {
} }
} }
boolean UBXcompareMsgHeader(const char* msgHeader) { bool UBXcompareMsgHeader(const char* msgHeader)
{
char* ptr = (char*)(&UBX.Message); char* ptr = (char*)(&UBX.Message);
return ptr[0] == msgHeader[0] && ptr[1] == msgHeader[1]; return ptr[0] == msgHeader[0] && ptr[1] == msgHeader[1];
} }
void UBXinitCFG(void){ void UBXinitCFG(void)
{
for (uint32_t i = 0; i < sizeof(UBLOX_INIT); i++) { for (uint32_t i = 0; i < sizeof(UBLOX_INIT); i++) {
UBXSerial->write( pgm_read_byte(UBLOX_INIT+i) ); UBXSerial->write( pgm_read_byte(UBLOX_INIT+i) );
} }
DEBUG_SENSOR_LOG(PSTR("UBX: turn off NMEA")); DEBUG_SENSOR_LOG(PSTR("UBX: turn off NMEA"));
} }
void UBXTriggerTele(void){ void UBXTriggerTele(void)
{
mqtt_data[0] = '\0'; mqtt_data[0] = '\0';
if (MqttShowSensor()) { if (MqttShowSensor()) {
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
@ -313,7 +319,6 @@ void UBXTriggerTele(void){
/********************************************************************************************/ /********************************************************************************************/
void UBXDetect(void) void UBXDetect(void)
{ {
if ((pin[GPIO_GPS_RX] < 99) && (pin[GPIO_GPS_TX] < 99)) { if ((pin[GPIO_GPS_RX] < 99) && (pin[GPIO_GPS_TX] < 99)) {
@ -340,7 +345,8 @@ void UBXDetect(void)
UBXTriggerTele(); // ... once at after start UBXTriggerTele(); // ... once at after start
} }
uint32_t UBXprocessGPS() { uint32_t UBXprocessGPS()
{
static uint32_t fpos = 0; static uint32_t fpos = 0;
static char checksum[2]; static char checksum[2];
static uint8_t currentMsgType = MT_NONE; static uint8_t currentMsgType = MT_NONE;
@ -353,20 +359,20 @@ uint32_t UBXprocessGPS() {
byte c = UBXSerial->read(); byte c = UBXSerial->read();
if ( fpos < 2 ) { if ( fpos < 2 ) {
// For the first two bytes we are simply looking for a match with the UBX header bytes (0xB5,0x62) // For the first two bytes we are simply looking for a match with the UBX header bytes (0xB5,0x62)
if ( c == UBX.UBX_HEADER[fpos] ) if ( c == UBX.UBX_HEADER[fpos] ) {
fpos++; fpos++;
else } else {
fpos = 0; // Reset to beginning state. fpos = 0; // Reset to beginning state.
} }
else { } else {
// If we come here then fpos >= 2, which means we have found a match with the UBX_HEADER // If we come here then fpos >= 2, which means we have found a match with the UBX_HEADER
// and we are now reading in the bytes that make up the payload. // and we are now reading in the bytes that make up the payload.
// Place the incoming byte into the ubxMessage struct. The position is fpos-2 because // Place the incoming byte into the ubxMessage struct. The position is fpos-2 because
// the struct does not include the initial two-byte header (UBX_HEADER). // the struct does not include the initial two-byte header (UBX_HEADER).
if ( (fpos-2) < payloadSize ) if ( (fpos-2) < payloadSize ) {
((char*)(&UBX.Message))[fpos-2] = c; ((char*)(&UBX.Message))[fpos-2] = c;
}
fpos++; fpos++;
if ( fpos == 4 ) { if ( fpos == 4 ) {
@ -436,8 +442,10 @@ uint32_t UBXprocessGPS() {
/********************************************************************************************\ /********************************************************************************************\
| * callback functions for the download | * callback functions for the download
\*********************************************************************************************/ \*********************************************************************************************/
#ifdef USE_FLOG #ifdef USE_FLOG
void UBXsendHeader(void) { void UBXsendHeader(void)
{
WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN); WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN);
WebServer->sendHeader(F("Content-Disposition"), F("attachment; filename=TASMOTA.gpx")); WebServer->sendHeader(F("Content-Disposition"), F("attachment; filename=TASMOTA.gpx"));
WSSend(200, CT_STREAM, F( WSSend(200, CT_STREAM, F(
@ -448,7 +456,8 @@ void UBXsendHeader(void) {
"<trk>\r\n<trkseg>\r\n")); "<trk>\r\n<trkseg>\r\n"));
} }
void UBXsendRecord(uint8_t *buf){ void UBXsendRecord(uint8_t *buf)
{
char record[100]; char record[100];
char stime[32]; char stime[32];
UBX_t::entry_t *entry = (UBX_t::entry_t*)buf; UBX_t::entry_t *entry = (UBX_t::entry_t*)buf;
@ -462,21 +471,26 @@ void UBXsendRecord(uint8_t *buf){
WebServer->sendContent_P(record); WebServer->sendContent_P(record);
} }
void UBXsendFooter(void){ void UBXsendFooter(void)
{
WebServer->sendContent(F("</trkseg>\n</trk>\n</gpx>")); WebServer->sendContent(F("</trkseg>\n</trk>\n</gpx>"));
WebServer->sendContent(""); WebServer->sendContent("");
Rtc.user_time_entry = false; // we have blocked the main loop and want a new valid time Rtc.user_time_entry = false; // we have blocked the main loop and want a new valid time
} }
/********************************************************************************************/ /********************************************************************************************/
void UBXsendFile(void){
void UBXsendFile(void)
{
if (!HttpCheckPriviledgedAccess()) { return; } if (!HttpCheckPriviledgedAccess()) { return; }
Flog->startDownload(sizeof(UBX.rec_buffer),UBXsendHeader,UBXsendRecord,UBXsendFooter); Flog->startDownload(sizeof(UBX.rec_buffer),UBXsendHeader,UBXsendRecord,UBXsendFooter);
} }
#endif //USE_FLOG #endif //USE_FLOG
/********************************************************************************************/ /********************************************************************************************/
void UBXSetRate(uint16_t interval){ void UBXSetRate(uint16_t interval)
{
UBX.Message.cfgRate.cls = 0x06; UBX.Message.cfgRate.cls = 0x06;
UBX.Message.cfgRate.id = 0x08; UBX.Message.cfgRate.id = 0x08;
UBX.Message.cfgRate.len = 6; UBX.Message.cfgRate.len = 6;
@ -498,8 +512,8 @@ void UBXSetRate(uint16_t interval){
UBX.state.log_interval = 10*interval; UBX.state.log_interval = 10*interval;
} }
void UBXSelectMode(uint16_t mode)
void UBXSelectMode(uint16_t mode){ {
DEBUG_SENSOR_LOG(PSTR("UBX: set mode to %u"),mode); DEBUG_SENSOR_LOG(PSTR("UBX: set mode to %u"),mode);
switch(mode){ switch(mode){
#ifdef USE_FLOG #ifdef USE_FLOG
@ -564,9 +578,11 @@ void UBXSelectMode(uint16_t mode){
UBX.mode.send_UI_only = true; UBX.mode.send_UI_only = true;
UBXTriggerTele(); UBXTriggerTele();
} }
/********************************************************************************************/ /********************************************************************************************/
bool UBXHandlePOSLLH(){ bool UBXHandlePOSLLH()
{
DEBUG_SENSOR_LOG(PSTR("UBX: iTOW: %u"),UBX.Message.navPosllh.iTOW); DEBUG_SENSOR_LOG(PSTR("UBX: iTOW: %u"),UBX.Message.navPosllh.iTOW);
if (UBX.state.gpsFix>1) { if (UBX.state.gpsFix>1) {
if (UBX.mode.filter_noise) { if (UBX.mode.filter_noise) {
@ -593,17 +609,18 @@ bool UBXHandlePOSLLH(){
return false; // no GPS-fix return false; // no GPS-fix
} }
void UBXHandleSTATUS(){ void UBXHandleSTATUS()
{
DEBUG_SENSOR_LOG(PSTR("UBX: gpsFix: %u, valid: %u"), UBX.Message.navStatus.gpsFix, (UBX.Message.navStatus.flags)&1); DEBUG_SENSOR_LOG(PSTR("UBX: gpsFix: %u, valid: %u"), UBX.Message.navStatus.gpsFix, (UBX.Message.navStatus.flags)&1);
if ((UBX.Message.navStatus.flags)&1) { if ((UBX.Message.navStatus.flags)&1) {
UBX.state.gpsFix = UBX.Message.navStatus.gpsFix; //only store fixed status if flag is valid UBX.state.gpsFix = UBX.Message.navStatus.gpsFix; //only store fixed status if flag is valid
} } else {
else{
UBX.state.gpsFix = 0; // without valid flag, everything is "no fix" UBX.state.gpsFix = 0; // without valid flag, everything is "no fix"
} }
} }
void UBXHandleTIME(){ void UBXHandleTIME()
{
DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time: %u-%u-%u %u:%u:%u"), UBX.Message.navTime.year, UBX.Message.navTime.month ,UBX.Message.navTime.day,UBX.Message.navTime.hour,UBX.Message.navTime.min,UBX.Message.navTime.sec); DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time: %u-%u-%u %u:%u:%u"), UBX.Message.navTime.year, UBX.Message.navTime.month ,UBX.Message.navTime.day,UBX.Message.navTime.hour,UBX.Message.navTime.min,UBX.Message.navTime.sec);
if (UBX.Message.navTime.valid.UTC) { if (UBX.Message.navTime.valid.UTC) {
DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time is valid")); DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time is valid"));
@ -735,8 +752,7 @@ void UBXShow(bool json)
dtostrfd((double)UBX.state.last_vAcc/1000.0f,3,hAcc); dtostrfd((double)UBX.state.last_vAcc/1000.0f,3,hAcc);
dtostrfd((double)UBX.state.last_hAcc/1000.0f,3,vAcc); dtostrfd((double)UBX.state.last_hAcc/1000.0f,3,vAcc);
if (json) if (json) {
{
ResponseAppend_P(PSTR(",\"GPS\":{")); ResponseAppend_P(PSTR(",\"GPS\":{"));
if (UBX.mode.send_UI_only) { if (UBX.mode.send_UI_only) {
uint32_t i = UBX.state.log_interval / 10; uint32_t i = UBX.state.log_interval / 10;
@ -775,12 +791,12 @@ void UBXShow(bool json)
} }
} }
/*********************************************************************************************\ /*********************************************************************************************\
* check the UBX commands * check the UBX commands
\*********************************************************************************************/ \*********************************************************************************************/
bool UBXCmd(void) { bool UBXCmd(void)
{
bool serviced = true; bool serviced = true;
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
UBXSelectMode(XdrvMailbox.payload); UBXSelectMode(XdrvMailbox.payload);
@ -793,8 +809,6 @@ bool UBXCmd(void) {
* Interface * Interface
\*********************************************************************************************/ \*********************************************************************************************/
#define XSNS_60 60
bool Xsns60(uint8_t function) bool Xsns60(uint8_t function)
{ {
bool result = false; bool result = false;

View File

@ -131,7 +131,8 @@ a_setoption = [[
"GroupTopic replaces %topic% (0) or fixed topic cmnd/grouptopic (1)", "GroupTopic replaces %topic% (0) or fixed topic cmnd/grouptopic (1)",
"Enable incrementing bootcount when deepsleep is enabled", "Enable incrementing bootcount when deepsleep is enabled",
"Do not power off if slider moved to far left", "Do not power off if slider moved to far left",
"","", "Bypass Compatibility check",
"",
"Enable shutter support", "Enable shutter support",
"Invert PCF8574 ports" "Invert PCF8574 ports"
],[ ],[
@ -187,7 +188,7 @@ a_features = [[
"USE_SHUTTER","USE_PCF8574","USE_DDSU666","USE_DEEPSLEEP", "USE_SHUTTER","USE_PCF8574","USE_DDSU666","USE_DEEPSLEEP",
"USE_SONOFF_SC","USE_SONOFF_RF","USE_SONOFF_L1","USE_EXS_DIMMER", "USE_SONOFF_SC","USE_SONOFF_RF","USE_SONOFF_L1","USE_EXS_DIMMER",
"USE_ARDUINO_SLAVE","USE_HIH6","USE_HPMA","USE_TSL2591", "USE_ARDUINO_SLAVE","USE_HIH6","USE_HPMA","USE_TSL2591",
"USE_DHT12","","","", "USE_DHT12","","USE_GPS","",
"","","","", "","","","",
"","","","" "","","",""
]] ]]