準備
コンパイル
この世界ではソースコードと言わずにスケッチというそうですHi。
このままでは動作しません。個別のハードウェア環境、APRS環境、ネットワーク環境に合わせたスケッチの修正が必要です
スケッチの最初の部分に個別設定がありますので、その部分を各自の環境に合わせて修正を行ってください。
最初に #include "jf6lze-13.h"
などの部分をコメントアウトしてください。私の個人的設定を読み込むようにしていますが、これは不要です。リリースタイミングによっては jg6ycl-13.h, jg6ycl-15.hを読み込むようにしているかもしれません。
/* -*- c -*- */ /* Temperature, Humidity, Pressure Web Server (JSON) and APRS Weather Station for ESP32 (ESP32-WROOM-32) Copyright (C) 2019,2020,2021 by JF6LZE. All Rights Reserved. 鐚 Multitask Version.. (2019.09.20-) $Id: esp32_bme280_webserver.ino,v 1.3 2022/01/02 07:26:56 yahiro Exp $ */ const char * ktwx_version = "0.08.0"; /* https://github.com/mgo-tec/ESP32_BME280_I2C https://github.com/mgo-tec/ESP32_BME280_I2C/archive/master.zip */ #include <ESP32_BME280_I2C.h> /* Copyright (c) 2015, Majenko Technologies All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * Neither the name of Majenko Technologies nor the names of its contributors may be used to endorse or promote product derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //#define USE_ARDUINO #include <WiFi.h> #include <WiFiMulti.h> #include <WiFiClient.h> #ifdef USE_ARDUINO #include <Ethernet.h> #else #include <WebServer.h> #include <HTTP_Method.h> #include <ESPmDNS.h> #endif #include <time.h> /* https://github.com/espressif/arduino-esp32 */ // ************************* // Configureation Section // // 潟潟ゃ絆邃梧┛include祿磧祿磚礒祟筰竍┏荐絎茵磽礒 // // ************************* // for TEST Configuration //#include "jf6lze-13.h" // ESP32 DevKit SS //#include "jg6ycl-13.h" // ESP32 DevKit Waves //#include "jg6ycl-15.h" // M5Stack //#include "jg6ycl-14.h" // 弱 ESP32 NodeE-MCU32 //#include "studyroom.h" // 弱 ESP32 NodeE-MCU32 //#include "dining_m5stack.h" // M5Stack NO APRS (with Network, Web Server) // // WiFi configuration (2.4GHz) // #ifndef DEF_CONF_WIFI #define DEF_CONF_WIFI const char *ssid = "AP-SSID"; const char * password = "secret-key"; #endif /* IP configuration DHCPP≪禮礫礬竇彰define USE_DHCP 阪IP經絲竢define USE_DHCP 潟<潟≪礒祟筮羆竇臂礒 */ //#define USE_DHCP #if !defined( USE_DHCP ) && !defined( DEF_CONF_IP ) #define DEF_CONF_IP IPAddress local_IP(192, 168, 1, 59); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); IPAddress primaryDNS(8, 8, 8, 8); IPAddress secondaryDNS(8, 8, 4, 4); #endif WiFiMulti wifiMulti; // // for APRS-IS // for Ham Radio // APRS-IS肆院羆邃拭禊絲#define USE_APRS鴻礒 // //#define USE_APRS #if defined( USE_APRS ) && !defined( DEF_CONF_APRS ) #define DEF_CONF_APRS const char * callsign_ssid = "NOCALL-13"; // 潟若禝磴SSID綽 const int passcode = 00000; // APRS-IS磚祚禹禮asscode // // 祉潟泣絎ゅ荐臀禊絎聿県礙羚水墾APRS-IS蜆拭礒秕祿秕祟 // 經絲邃梧┏閻ぐ 0 礒 // 乗PRSс竊県綺羚水墾腥冴若帥礙祚粭т硯礫秕 const int send_humidity = 1; const int send_temperature = 1; // Your Location const float lat = 33.0000; // 膩綺 const float lng = 130.0000; // 腟綺 const float altitude = 75; // altitude [m] // 罔蕭 [m] 鐚羂с蒿g // Upstream APRS-IS const char * host = "wave.ftokai-u.ac.jp"; // Old-T2FUKUOKA or fukuoka.aprs2.net const uint16_t port = 14580; const int aprs_update_interval = 5; // 贋育 [] #endif // // WebServer罘純鴻禊 #define USE_WEBSERVER 鴻礒 // //#define USE_WEBSERVER // // // //#define USE_DEEP_SLEEP // // // // ESP32 and MBE280 Hardware configuration // #ifndef DEF_CONF_GPIO #define DEF_CONF_GPIO const uint8_t Address = 0x76; //const uint8_t Address = 0x77; // // BME280 SDA, SCLョGPIO絋經礒 // ョGPIO絋經礒 // // 腮箝莉PIO (ESP32) // 6,7,8,9,10,11,15 箍禹禹 // M5Stack經繙<PIO紲礑紿腮礒礬腮礑秕 // 0,1,3,18,19,23,25 // LCD≫ 14,18,23,27,33 // 34-39 INPUT // M5Stack經綮祿禝禺礙礒https://amzn.to/34NHbXi 篏帥翫邃梧┴禮禮 // BME2805Stack礑磚礒竢M5Stack膠祟綵運礒竇幻祕綺羝綺Γ礒蒿謙礒秕秕 // 鐚Grove SDA, SCLャ帥荐紮Grove篏窮禊絲羈鐚 // const uint8_t sda = 22; // const uint8_t scl = 21; // 箝竏君絣竏申磽礒 // https://github.com/m5stack/M5-Schematic/blob/master/Core/Basic/M5-Core-Schematic(20171206).pdf const uint8_t sda = 21; const uint8_t scl = 22; //const uint8_t sda = 32; //const uint8_t scl = 33; // // LED configureation // LEDョ禊絲0絎 // M5Stack經3紿腮 const uint8_t busy_led = 0; #endif #if !defined( DEF_CONF_USE_ANALOG ) #define DEF_CONF_USE_ANALOG // // ≪祕禹祿禝礇膣絲#define USE_ANALOG 絎臂礒 // #define USE_ANALOG const int analog_gpio[] = { 34, 35 }; #endif #if !defined( DEF_CONF_MORSE_LED ) #define DEF_CONF_MORSE_LED // // 羂羝礫礬磚禺祀禮篆〃LED鐚ч #define USE_MORSE_LED const uint8_t morse_led = busy_led; const uint8_t morse_speed = 200; // 医ゃ絨薨秕 #endif // // M5Stack腮禊絲USE_M5STACK絎臂ESP32冴若經絲祿磧祿磚礒 //#define USE_M5STACK #define LCD_BRIGHTNESS 150 #define USE_M5STACK_POWER_CONTROL #if !defined( DEF_CONF_USE_LCD_SSD1306 ) #define DEF_CONF_USE_LCD_SSD1306 // // // https://amzn.to/2ntemy9 篏帥翫邃梧┨祀礒竢執邃賢 //#define USE_LCD_SSD1306 // #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels #endif #if !defined( DEF_CONF_USE_MQTT ) #define DEF_CONF_USE_MQTT // MQTT肆院禺秧邃拭禊絲USE_MQTT絎臂礒 // 磴礬礫禺祚https://github.com/knolleary/pubsubclient // #define USE_MQTT const char * mqtt_host = "ketaitracker.info"; const int mqtt_port = 1883; const char * mqtt_topic_prifix = "aprs/wx"; char mqtt_topic[256]; // = "aprs/wx/dummy"; // test now #endif #ifndef DEF_CONF_USE_OTA #define DEF_CONF_USE_OTA // // OTA腮禊define USE_OTA鴻礒 // Bluetooth腟宴с祕礬祟羇羂礑祀礫秕 #define USE_OTA #endif ///////////////////////////// // // 篁ヤ紊眼繖梧Η // ///////////////////////////// #ifdef USE_OTA #include <WiFiUdp.h> #include <ArduinoOTA.h> #endif #if defined( USE_APRS ) const char * mdns_name = callsign_ssid; #else const char * mdns_name = "esp32-wx"; #endif #ifdef USE_DEEP_SLEEP #undef USE_WEBSERVER #endif #ifdef USE_M5STACK #include <M5Stack.h> #endif long timezone = 0; byte daysavetime = 0; #ifdef USE_WEBSERVER #ifdef USE_ARDUINO EthernetServer server(80); #else WebServer server(80); #endif #endif #ifdef USE_APRS WiFiClient aprs; #endif #ifdef USE_MQTT // // сMQTT_MAX_PACKET_SIZE 紊眼礬磴礬礫禺祀綵運秕 // ~/Document/Arduino/libraries/pubsubclient-master/src/PubSubClient.h // #define MQTT_MAX_PACKET_SIZE 256 經礒 //#define MQTT_MAX_PACKET_SIZE 256 #include <PubSubClient.h> WiFiClient wifiClient; PubSubClient mqttClient(wifiClient); #endif #define STATUS_BUSY 1 #define STATUS_IDLE 0 // // LCD SSD1306 #if defined( USE_LCD_SSD1306 ) #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #ifndef SCREEN_WIDTH #define SCREEN_WIDTH 128 #endif #ifndef SCREEN_HEIGHT #define SCREEN_HEIGHT 32 // OLED display height, in pixels #endif #define USE_LCD #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); #endif // end if USE_LCD_SSD1306 #if defined( USE_M5STACK ) #undef USE_LCD #endif //const int led = 13; const uint32_t frequency = 30000; ESP32_BME280_I2C bme280i2c(Address, scl, sda, frequency); // // mean-sea-level barometric pressure // double adjustPressure( double pressure, double temperature, double altitude ) { return pressure * pow( 1 - 0.0056 * altitude / ( temperature + 0.0065 * altitude + 273.15), 5.257 ); } void setup(void) { unsigned long system_start_time = millis(); unsigned long system_ready_time; Serial.begin(115200); Serial.println( ); #if defined( __AVR__ ) Serial.println( "ARDUINO Enabled" ); #endif #if defined( ESP32 ) Serial.println( "ESP32 Enabled" ); #endif #if defined( ESP8266 ) Serial.printlmn( "ESP8266 Enabled" ); #endif #if defined( USE_LCD ) || defined( USE_LCD_SSD1306 ) Serial.println( "LCD_SSD1306 Enabled" ); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for (;;); // Don't proceed, loop forever } display.display(); display.clearDisplay(); display.setTextSize( 1 ); display.setTextColor( WHITE ); display.setCursor( 0, 0 ); display.printf( "%s", "KetaiTracker ESP" ); display.setCursor( 0, 10 ); display.setTextSize( 2 ); display.printf( "%s", ktwx_version ); display.display(); #endif #ifdef USE_M5STACK if ( sda == 25 || scl == 25 || busy_led == 25 ) { // M5Stack5綺紲綉禮禺祀禺祟礑蒿絵. Serial.println( "Error: Don't use GPIO 25" ); } #endif #ifndef USE_ARDUINO pinMode( sda, PULLUP ); pinMode( scl, PULLUP ); #endif if ( busy_led != 0 ) pinMode( busy_led, OUTPUT ); #ifdef USE_MORSE_LED if ( morse_led != 0 ) pinMode( morse_led, OUTPUT ); #endif Serial.println( "" ); #ifdef USE_M5STACK Serial.println( "M5STACK" ); M5.begin(); //M5.Speaker.begin(); //M5.Speaker.end(); M5.Lcd.println( "KetaiTracker WX" ); #ifdef USE_M5STACK_POWER_CONTROL if ( M5.Power.canControl()) { M5.Lcd.println( "Contorable Power" ); if ( M5.Power.isChargeFull()) { M5.Lcd.print( "Battery: full" ); } else { M5.Lcd.print( "Battery: NOT full" ); } M5.Lcd.printf( ",%d%% ", M5.Power.getBatteryLevel()); if ( M5.Power.isCharging()) { M5.Lcd.println( ", Charging Now" ); } else { M5.Lcd.println( "" ); } } else { M5.Lcd.println( "Power Control is disbaled (May be.. Old M5Stack)" ); } #endif #ifdef USE_APRS M5.Lcd.printf( "Callsign: %s\n", callsign_ssid ); #endif #endif #ifdef USE_MQTT sprintf( mqtt_topic, "%s/%s", mqtt_topic_prifix, callsign_ssid ); Serial.printf( "MQTT publish enabled %s:%d, topic: %s\n", mqtt_host, mqtt_port, mqtt_topic ); Serial.printf( "MQTT maximum message size is %d, keepalive interval is %d\n", MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE ); #endif statusLed( STATUS_BUSY ); #ifdef USE_MORSE_LED Serial.println( "Morse LED Enabled" ); #endif #ifdef USE_WEBSERVER Serial.println( "Web Server Enabled" ); #endif #ifdef USE_APRS Serial.println( "APRS Weather Station Enbaled" ); #endif #ifdef USE_ANALOG Serial.println( "Analog Input Enabled" ); #endif #ifdef USE_DHCP Serial.println( 'use DHCP Server' ); #else Serial.println( 'use Static IP Address' ); if ( !WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) { Serial.println("STA Failed to configure"); } #endif #if 1 initWiFi(); #else WiFi.mode( WIFI_STA ); WiFi.begin( ssid, password); #endif Serial.println(""); /* Serial.print( "Reconned mode is " ); Serial.println( WiFi.getAutoReconnect() ); */ // Wait for connection #if 0 keepWifi(); Serial.println( "" ); Serial.print( "Connected to " ); Serial.println(ssid); Serial.print( "IP address: " ); Serial.println( WiFi.localIP() ); #endif #ifdef USE_M5STACK M5.Lcd.print( "IP: " ); M5.Lcd.println( WiFi.localIP()); #endif if ( MDNS.begin( mdns_name )) { Serial.printf("MDNS responder started : %s.local\n", mdns_name ); } // BME280 //Example Indoor navigation uint8_t t_sb = 0; //stanby 0.5ms uint8_t filter = 4; //IIR filter = 16 uint8_t osrs_t = 2; //OverSampling Temperature x2 uint8_t osrs_p = 5; //OverSampling Pressure x16 uint8_t osrs_h = 1; //OverSampling Humidity x1 uint8_t Mode = 3; //Normal mode bme280i2c.ESP32_BME280_I2C_Init(t_sb, filter, osrs_t, osrs_p, osrs_h, Mode); Wire.begin(); // I2C check if ( 1 ) { Wire.beginTransmission( Address ); byte error = Wire.endTransmission(); if ( error != 0 ) { #ifdef USE_M5STACK M5.Lcd.printf( "Error: Not found BME280 at 0x%x\n", Address ); #endif Serial.printf( "Error: Not found BME280 at 0x%x\n", Address ); msgError(); } } syncNtp(); struct tm tmstruct ; // delay(2000); tmstruct.tm_year = 0; getLocalTime(&tmstruct, 5000); Serial.printf("Now %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct.tm_year) + 1900, ( tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec ); Serial.println(""); #ifdef USE_M5STACK M5.Lcd.printf( "Time: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct.tm_year) + 1900, ( tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec ); #endif #ifdef USE_WEBSERVER server.on( "/", putBme280Json); server.on( "/bme", putBme280Json ); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); #ifdef M5STACK M5.Lcd.println( "HTTP Server Started" ); #endif #endif statusLed( STATUS_IDLE ); #if defined( USE_M5STACK ) || defined( USE_LCD ) lcdWakeup(); // M5.Lcd.println( "" ); initLcd(); // 篁ラM5.Lcd.print激禺禳祚紿腮礫 // dispLcd( x, y, size, fmt, ... ); // dispLcdColor( x, y, size, color, fmt, ... ); #endif #if defined( USE_OTA ) initOta(); #endif Serial.print( "Setup() Core is is " ); Serial.println( xPortGetCoreID() ); #if defined( USE_MQTT ) //connectMqtt(); #endif xTaskCreatePinnedToCore(taskSystem, "taskSystem", 8192, NULL, 10 /* Priolity */ , NULL, 1 /* Core ID */); #if defined( USE_WEBSERVER ) && !defined( USE_DEEP_SLEEP ) xTaskCreatePinnedToCore(taskWebServer, "taskWebServer", 8192, NULL, 5 /* Priolity */ , NULL, 1 /* Core ID */); #endif #if defined( USE_APRS ) && !defined( USE_DEEP_SLEEP ) xTaskCreatePinnedToCore(taskAprs, "taskAprs", 8192, NULL, 20 /* Priolity */ , NULL, 1 /* Core ID */); #endif #if defined( USE_MORSE_LED ) if ( morse_led > 0 ) { #if defined( USE_APRS ) setMorse( callsign_ssid ); #endif xTaskCreatePinnedToCore(taskMorseLed, "taskMorseLed", 8192, NULL, 10 /* Priolity */ , NULL, 1 /* Core ID */); } #endif #if defined( USE_MQTT ) //xTaskCreatePinnedToCore(taskMqtt, "taskMqtt", 8192, NULL, 40 /* Priolity */ , NULL, 1 /* Core ID */); #endif #ifdef USE_DEEP_SLEEP send_aprs(); delay(2000); aprs.stop(); Serial.println( "Goto Deep Sleep" ); esp_deep_sleep( aprs_update_interval * 60000000 - ( millis() - system_start_time ) * 1000 ); #else delay(1000); #endif } void loop(void) { #ifndef USE_DEEP_SLEEP keepWifi(); #endif delay( 10000 ); //Serial.println( "loop()" ); } void initWiFi() { int n; char * ssid, * password; char buf[256]; n = sizeof( ap_list ) / sizeof( char * ); //USE_SERIAL.println( n ); for ( int i = 0 ; i < n ; i++ ) { sprintf( buf, "%s", ap_list[i] ); ssid = strtok( buf, "," ); password = strtok( NULL, "," ); wifiMulti.addAP( ssid, password ); } WiFi.config( local_IP, gateway, subnet, primaryDNS ); Serial.println("Connecting Wifi..."); if (wifiMulti.run() == WL_CONNECTED) { Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } } int readThpAvg( double * t, double * p, double * h ) { double temperature = 0.0, humidity = 0.0, pressure = 0.0; double t_t, t_h, t_p ; int c = 0 ; int n = 30; // 緇 int i; for ( i = 0 ; i < n ; i++ ) { c = 0; do { bme280i2c.Read_All( &t_t, &t_p, &t_h); delay( 10 ); c++; if ( c > 40 ) { ESP.restart(); } } while ( t_h == 0 || t_h == 100 ); temperature += t_t; humidity += t_h; pressure += t_p; } * t = temperature / n; * p = pressure / n; * h = humidity / n; return 0; } int readThp( double * t, double * p, double * h ) { double temperature, humidity, pressure; int c = 0 ; do { bme280i2c.Read_All( &temperature, &pressure, &humidity); delay( 250 ); c++; if ( c > 40 ) { ESP.restart(); } } while ( humidity == 0 || humidity == 100 ); * t = temperature; * p = pressure; * h = humidity; return 0; } void msgError() { int cnt = 0; Serial.println( "abort system due to ERROR" ); #ifdef USE_M5STACK M5.Lcd.printf( "Abort system due to error\n" ); while ( 1 ) { delay( 1000 ); } #else while ( 1 ) { if ( busy_led != 0 ) { digitalWrite( busy_led, HIGH ); if ( morse_led != 0 && morse_led != busy_led ) digitalWrite( morse_led, LOW ); delay( 50 ); digitalWrite( busy_led, LOW ); if ( morse_led != 0 && morse_led != busy_led ) digitalWrite( morse_led, HIGH ); delay( 50 ); } cnt++; if ( cnt > 100 ) ESP.restart(); } #endif } // // System Loop Task // display Clock and Tenperature, Humidity void taskSystem( void * arg ) { static time_t nextMorse = 0; static boolean setNextMorse = true; Serial.print( "taskSystem() Core is is " ); Serial.println( xPortGetCoreID() ); while ( 1 ) { //Serial.println( "taskSystem() loop" ); #if defined( USE_M5STACK ) M5.update(); if ( M5.BtnA.isPressed() ) { lcdWakeup(); } if ( M5.BtnC.isPressed() ) { lcdSleep(); } dispStatus(); lcdAutoSleep(); #endif #if defined( USE_LCD ) dispStatus(); #endif #if defined( USE_MORSE_LED ) if (setNextMorse && now() > nextMorse ) { setNextMorse = false; statusMorse(); } if ( !setNextMorse && getMorseQueN() == 0 ) { // Serial.println( "set NextMorse time" ); setNextMorse = true; nextMorse = now() + 30; } #endif #if defined( USE_OTA ) ArduinoOTA.handle(); #endif delay( 100 ); } } #if defined( USE_WEBSERVER ) // // WebServer Task // void taskWebServer( void * arg ) { Serial.print( "taskWebServer() Core is is " ); Serial.println( xPortGetCoreID() ); while ( 1 ) { server.handleClient(); delay( 30 ); } } #endif #if defined( USE_APRS ) // // APRS≫秧禮 // void taskAprs( void * arg ) { static time_t packet_send_time = 0; int c; Serial.print( "taskAprs() Core is is " ); Serial.println( xPortGetCoreID() ); while ( 1 ) { while ( aprs.available()) { c = aprs.read(); // Serial.print( aprs.read()); } //Serial.println( "taskAprs() loop" ); if ( now() > packet_send_time ) { packet_send_time = now() + 60 * aprs_update_interval; // 5min send_aprs(); } delay( 1000 ); } } #endif #if defined( USE_MQTT ) void taskMqtt( void * arg ) { static time_t send_time = 0; delay( 1500 ); while ( 1 ) { if ( now() > send_time ) { send_time = now() + 29; /* 30 sec interval */ // delay( 1000 ); sendMqtt(); } delay( 1000 ); } } boolean sendMqtt() { double temperature, humidity, pressure; char buf[256]; readThpAvg( &temperature, &pressure, &humidity); if ( pressure == 0 ) { Serial.println( "taskMqtt(): illegal data (humidity is zero)" ); } else { //sprintf( buf, "{\"callsign\":\"%s\",\"temperature\":%.2lf,\"humidity\":%.2lf,\"pressure\":%.2lf,\"time\":%ld}", callsign_ssid, temperature, humidity, pressure, now() ); sprintf( buf, "{\"callsign\":\"%s\",\"temperature\":%lf,\"humidity\":%.lf,\"pressure\":%lf,\"time\":%ld,\"latitude\":%f,\"longitude\":%f}", callsign_ssid, temperature, humidity, pressure, now() , lat, lng); if ( (strlen( buf ) + 2 + MQTT_MAX_HEADER_SIZE + strlen( mqtt_topic )) > MQTT_MAX_PACKET_SIZE ) { Serial.printf( "MQTT over max packet size (%d) < (%d) packet is %s\n", MQTT_MAX_PACKET_SIZE, strlen( buf ), buf ); return false; } Serial.printf( "MQTT sending..size %d.", strlen( buf ) ); keepWifi(); keepMqtt(); if ( mqttClient.publish( mqtt_topic, buf ) == false ) { Serial.println( "MQTT send fail" ); } mqttClient.loop(); Serial.println( "..done" ); } return true; } void keepMqtt() { if ( !mqttClient.connected()) connectMqtt(); } void connectMqtt() { mqttClient.setServer( mqtt_host, mqtt_port ); while ( ! mqttClient.connected() ) { Serial.printf("Connecting to MQTT...%s:%d ", mqtt_host, mqtt_port ); String clientId = "ESP32-" + String(random(0xffff), HEX); if ( mqttClient.connect(clientId.c_str()) ) { Serial.println("connected"); } delay(1000); randomSeed(micros()); } } #endif #if defined( USE_MORSE_LED ) void taskMorseLed( void * arg ) { while ( 1 ) { doMorseLed(); delay( 330 ); } } #endif // // NTP泣若祟繹秧竇篋障у // void syncNtp() { time_t t; int cnt = 0; Serial.print("Contacting Time Server"); #ifdef USE_M5STACK M5.Lcd.println( "Connecting to Time Server..." ); #endif configTime(3600 * timezone, daysavetime * 3600, "ntp.jst.mfeed.ad.jp", "time.google.com", "ntp.nict.jp" ); // configTime薈鐚 delay礬礑竍綺紕礒竇粋 do { time( &t ); Serial.print( t ); Serial.print( ", " ); delay( 1000 ); cnt++; if ( cnt > 30 ) { Serial.println( "Reboot due to fail (Sync NTP)" ); ESP.restart(); } } while ( t < 1000 ); // 禮竊c祚 Serial.println( " done." ); } time_t now() { time_t t; time( &t ); return t; } void statusLed( int sw ) { static int cnt = 0; if ( sw > 0 ) cnt++; else cnt--; /* Serial.print( "statusLed() &c =" ); char buf[30]; sprintf( buf, "%ld", &cnt ); Serial.print( buf ); Serial.print( ", " ); Serial.print( cnt ); Serial.println( "" ); */ #ifdef USE_M5STACK // M5.Lcd.fillEllipse( 310, 10, 10, 10, s > 0 ? TFT_RED : TFT_GREEN ); M5.Lcd.setTextSize( 1 ); if ( cnt > 0 ) { /* budy */ M5.Lcd.setTextColor( TFT_WHITE, TFT_RED ); } else { M5.Lcd.setTextColor( TFT_WHITE, TFT_DARKGREEN ); } M5.Lcd.setCursor( 290, 0 ); M5.Lcd.print( cnt > 0 ? "Busy" : "Idle" ); M5.Lcd.setTextColor( TFT_WHITE, TFT_BLACK ); #endif if ( busy_led == 0 ) return; digitalWrite( busy_led, cnt > 0 ? HIGH : LOW ); } void keepWifi() { #if 1 int retry = 0; while (WiFi.status() != WL_CONNECTED) { delay(2000); wifiMulti.run(); Serial.print( WiFi.status() ); retry++; if ( retry > 10 ) { Serial.println( "" ); Serial.println( "Restart system due to fail wifi connection" ); #ifdef USE_M5STACK M5.Lcd.printf( "Restart System due to fail Wifi connection\n" ); delay( 3000 ); #endif ESP.restart(); } } #else int retry = 0; while (WiFi.status() != WL_CONNECTED) { delay(2000); WiFi.begin(); Serial.printf(" Wifi. %s ", ssid ); Serial.print( WiFi.status() ); retry++; if ( retry > 10 ) { Serial.println( "" ); Serial.println( "Restart system due to fail wifi connection" ); #ifdef USE_M5STACK M5.Lcd.printf( "Restart System due to fail Wifi connection\n" ); delay( 3000 ); #endif ESP.restart(); } } #endif } #ifdef USE_APRS void send_aprs() { String packet; double temperature, pressure, humidity, pressure_adj; String msg; char pos[30]; char timestr[30]; char sendtimestr[30]; struct tm tmstruct ; #ifdef USE_M5STACK lcdWakeup(); #endif statusLed( STATUS_BUSY ); getLocalTime(&tmstruct, 5000); sprintf( sendtimestr, "%d-%02d-%02d %02d:%02d:%02d", (tmstruct.tm_year) + 1900, ( tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec ); Serial.printf("Now %s\n", sendtimestr ); sprintf( timestr, "%02d%02d%02dz", tmstruct.tm_mday, tmstruct.tm_hour , tmstruct.tm_min ); // connect to aprs-id if ( !aprs.connected()) { #ifdef USE_M5STACK dispLcd( 0, 190, 1, "Connecting to APRS-IS %s:%d", host, port ); #endif if (!aprs.connect(host, port)) { Serial.println("connection failed"); statusLed( STATUS_IDLE ); return; } Serial.printf( "connected to APRS-IS %s:%d\n", host, port ); #ifdef USE_M5STACK dispLcd( 0, 190, 1, "Connected to APRS-IS %s:%d", host, port ); #endif if ( aprs.connected()) { char cmd[256]; sprintf( cmd, "user %s pass %d vers KetaiTrackerWX %s ESP32+BMP280", callsign_ssid, passcode, ktwx_version ); aprs.println( cmd ); Serial.println( cmd ); delay( 100 ); while ( aprs.available() == 0 ) { Serial.print( 'wait.' ); delay( 100 ); } String line = aprs.readStringUntil('\r'); Serial.print(line); } } readThpAvg(&temperature, &pressure, &humidity); pressure_adj = adjustPressure( pressure, temperature, altitude ); //Serial.println ( pressure ); //Serial.println ( pressure_adj ); char temp_c[10], hum_c[10], pres_c[10]; if ( send_temperature ) { sprintf( temp_c, "t%03.0lf", temperature * 9 / 5.0 + 32 ); } else { sprintf( temp_c, "t..." ); } if ( send_humidity ) { sprintf( hum_c, "h%02.0lf", humidity); } else { sprintf( hum_c, "h.." ); } sprintf( pres_c, "b%05.0lf", pressure_adj * 10); sprintf( pos, "%02d%05.2fN/%03d%05.2fE", (int)lat, (lat - (int)lat) * 60.0, (int)lng, (lng - (int)lng) * 60.0 ); char p[60]; sprintf( p, "%s>APPT30,TCPIP*:", callsign_ssid ); packet = p; if ( 0 ) { packet += "!"; } else { packet += "@"; packet += timestr; } packet += pos; packet += "_"; // packet += "000 / 000"; packet += ".../..."; //packet += "c...s...g..."; // Wind //packet += "c000s000g000"; packet += temp_c; packet += hum_c; packet += pres_c; //packet += " ESP32 + BME280"; Serial.println( packet ); #ifdef USE_M5STACK M5.Lcd.setTextSize( 1 ); M5.Lcd.setCursor( 0, 180 ); M5.Lcd.printf( "%s UTC", sendtimestr ); M5.Lcd.setCursor( 0, 200 ); M5.Lcd.print( "Sending: " ); M5.Lcd.println( packet ); #endif aprs.println( packet ); if ( 0 ) { //aprs.flush(); // Disconnect秕秧 delay(1000); //aprs.stop(); // Disconnect } statusLed( STATUS_IDLE ); } #endif // end of #USE_APRS #ifdef USE_ANALOG char * getAnalogJson() { // TODO: 緇ャC++ c純吾眼 // 鴻祕祟秕秕 static char buf[256]; String msg; int i, n; n = sizeof( analog_gpio ) / sizeof( int ); msg = "\"analog\":["; for ( i = 0; i < n ; i++ ) { if ( i != 0 ) msg += ","; msg += analogRead( analog_gpio[i] ); } msg += "]"; snprintf( buf, 256, "%s", msg.c_str() ); //Serial.println( buf ); return buf; } int * getAnalog() { static int buf[10]; // TODO: 緇ャC++ c純吾眼 // 鴻祕祟秕秕 int i, n; n = sizeof( analog_gpio ) / sizeof( int ); for ( i = 0; i < n ; i++ ) { buf[i] = analogRead( analog_gpio[i] ); } return buf; } #endif #ifdef USE_WEBSERVER void handleNotFound() { //digitalWrite(led, 1); String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send( 404, "text/plain", message); // digitalWrite(led, 0); } /* Web Server JSON綵√鐚羂с蜈墾蒿c茯 */ void putBme280Json() { double temperature, pressure, humidity; String msg; char temp_c[10], hum_c[10], pres_c[10]; statusLed( STATUS_BUSY ); server.sendHeader( "Access-Control-Allow-Origin", "*" ); server.sendHeader( "Cache-Control", "no-cache"); readThpAvg(&temperature, &pressure, &humidity); sprintf(temp_c, "%.2lf", temperature); sprintf(hum_c, "%.2lf", humidity); sprintf(pres_c, "%.2lf", pressure); msg = "{\"temperature\":"; msg += temp_c; msg += ",\"humidity\":" ; msg += hum_c; msg += ",\"pressure\":"; msg += pres_c; // msg += ",\"dummy\":123"; #ifdef USE_ANALOG msg += ","; msg += getAnalogJson(); #endif msg += ",\"version\":"; msg += "\""; msg += ktwx_version; msg += "\"" ; msg += "}"; //msg += "\n"; server.send( 200, "application/json", msg ); //server.send( 200, "text/plain", msg ); //delay( 500 ); statusLed( STATUS_IDLE ); } #endif #if defined( USE_M5STACK ) || defined( USE_LCD ) void initLcd() { #if defined( USE_M5STACK ) M5.Lcd.setBrightness( LCD_BRIGHTNESS ); M5.Lcd.clear(); dispLcd( 0, 0, 1, "KetaiTracker WX %s", ktwx_version ); dispLcd( 160, 0, 1, "IP: %s", WiFi.localIP().toString().c_str() ); #ifdef USE_APRS dispLcd( 0, 10 , 1, "Callsign: %s", callsign_ssid ); dispLcd( 0, 18, 1, "APRS-IS: %s:%d", host, port ); #endif initGraph(); #endif #if defined( USE_LCD ) display.clearDisplay(); display.display(); #endif } // // #ifndef SLEEP_TIME #define SLEEP_TIME 0 #endif time_t nextSleepTime = 0; time_t lcdSleepTime = SLEEP_TIME; boolean isSleep = false; void lcdSleep() { #if defined( USE_M5STACK ) if ( isSleep ) return; isSleep = true; if ( lcdSleepTime > 5 ) { for ( int i = LCD_BRIGHTNESS; i > 10; i-- ) { M5.Lcd.setBrightness(i); delay( 15 ); } } M5.Lcd.sleep(); M5.Lcd.setBrightness(0); #endif Serial.println( "LCD sleep" ); } void lcdWakeup() { #if defined( USE_M5STACK ) lcdResetSleep(); if ( !isSleep ) return; isSleep = false; M5.Lcd.wakeup(); M5.Lcd.setBrightness(LCD_BRIGHTNESS); Serial.println( "LCD Wakeup" ); #endif } void lcdResetSleep() { nextSleepTime = now() + lcdSleepTime; } void lcdAutoSleep() { if ( lcdSleepTime == 0 ) return; if ( now() > nextSleepTime ) { lcdSleep(); } } void dispLcd( uint16_t x, uint16_t y, uint16_t size, const char * fmt, ... ) { char buf[1024]; va_list arg; va_start(arg, fmt ); vsnprintf( buf, 1024, fmt, arg ); #if defined( USE_M5STACK ) M5.Lcd.setCursor( x, y ); M5.Lcd.setTextSize( size ); M5.Lcd.print( buf ); #endif #if defined( USE_LCD ) display.setCursor( x, y ); display.setTextSize( size ); display.print( buf ); display.display(); #endif va_end(arg); } void dispLcdColor( uint16_t x, uint16_t y, uint16_t size, uint16_t color, const char * fmt, ... ) { char buf[1024]; va_list arg; va_start(arg, fmt ); vsnprintf( buf, 1024, fmt, arg ); #if defined( USE_M5STACK ) M5.Lcd.setTextColor( color, TFT_BLACK ); M5.Lcd.setCursor( x, y ); M5.Lcd.setTextSize( size ); M5.Lcd.print( buf ); #endif #if defined( USE_LCD ) display.setTextColor( color, BLACK ); display.setCursor( x, y ); display.setTextSize( size ); display.print( buf ); display.display(); #endif va_end(arg); } void dispLcdColorBg( uint16_t x, uint16_t y, uint16_t size, uint16_t color, uint16_t bgcolor, const char * fmt, ... ) { char buf[1024]; va_list arg; va_start(arg, fmt ); vsnprintf( buf, 1024, fmt, arg ); #if defined( USE_M5STACK ) M5.Lcd.setTextColor( color, bgcolor ); M5.Lcd.setCursor( x, y ); M5.Lcd.setTextSize( size ); M5.Lcd.print( buf ); #endif #if defined( USE_LCD ) display.setTextColor( color, bgcolor ); display.setCursor( x, y ); display.setTextSize( size ); display.print( buf ); display.display(); #endif va_end(arg); } #if !defined( USE_M5STACK ) #define TFT_RED WHITE #define TFT_WHITE WHITE #define TFT_GREEN WHITE #define TFT_CYAN WHITE #endif #define COLOR_TEMPERATURE TFT_RED #define COLOR_HUMIDITY TFT_CYAN #define COLOR_PRESSURE TFT_GREEN #define COLOR_INC TFT_ORANGE #define COLOR_DEC TFT_CYAN #define DATA_STACK 600 double calc_avg( double v[], int n ) { int i; double t = 0.0; for ( i = 0 ; i < DATA_STACK && i < n ; i++ ) { t += v[i]; } return t / i; } void dispStatus() { static time_t nextUpdate = 0; // TODO: 罕篏篏帥c禮祗礫 double temperature, pressure, humidity; static double temperature_max = -99.0, pressure_max = 0.0, humidity_max = 0.0; static double temperature_min = 99.9, pressure_min = 2000.0, humidity_min = 100.0; static double temperature_prev = 0, pressure_prev = 0, humidity_prev = 0; static double temperature_stack[DATA_STACK], pressure_stack[DATA_STACK], humidity_stack[DATA_STACK]; static int data_stack = 0; static int data_stack_p ; uint16_t fg_t, fg_h, fg_p; uint16_t bg_t_max, bg_t_min, bg_p_max, bg_p_min, bg_h_max, bg_h_min; int x, y; if ( nextUpdate > now()) return; nextUpdate = now() + 1; // Current time struct tm tmstruct ; getLocalTime(&tmstruct, 5000); /* M5.Lcd.setCursor( 0, 140 ); M5.Lcd.setTextSize( 1 ); M5.Lcd.printf( "%d-%02d-%02d %02d:%02d:%02d", (tmstruct.tm_year) + 1900, ( tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec ); */ dispLcdColor( 0, 140, 1, TFT_WHITE, "%d-%02d-%02d %02d:%02d:%02d UTC", (tmstruct.tm_year) + 1900, ( tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); // #if defined( USE_LCD ) dispLcdColor( 0, 25, 1, WHITE, "%d/%02d/%02d %02d:%02d:%02d Z", (tmstruct.tm_year) + 1900, ( tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); #endif readThp(&temperature, &pressure, &humidity); /* M5.Lcd.setCursor( 0, 150 ); M5.Lcd.setTextSize( 2 ); M5.Lcd.printf( "T:%s H:%s P:%s", temp_c, hum_c, pres_c ); */ //dispLcd( 0, 150, 2, "T:%s H:%s P:%s", temp_c, hum_c, pres_c ); #if defined( USE_M5STACK ) /* char temp_c[10], hum_c[10], pres_c[10]; sprintf(temp_c, "%5.2lf", temperature); sprintf(hum_c, "%5.2lf", humidity); sprintf(pres_c, "%7.2lf", pressure); */ /* サ鐚綛喝 */ data_stack_p = data_stack % DATA_STACK; temperature_stack[data_stack_p] = temperature; humidity_stack[data_stack_p] = humidity; pressure_stack[data_stack_p] = pressure; data_stack++; fg_t = fg_h = fg_p = TFT_WHITE; if ( data_stack >= DATA_STACK || 1) { temperature_prev = calc_avg( temperature_stack, data_stack ); humidity_prev = calc_avg( humidity_stack, data_stack ); pressure_prev = calc_avg( pressure_stack, data_stack ); if ( temperature > temperature_prev ) fg_t = COLOR_INC; if ( temperature < temperature_prev ) fg_t = COLOR_DEC; if ( humidity > humidity_prev ) fg_h = COLOR_INC; if ( humidity < humidity_prev ) fg_h = COLOR_DEC; if ( pressure > pressure_prev ) fg_p = COLOR_INC; if ( pressure < pressure_prev ) fg_p = COLOR_DEC; } y = 150; x = 20; dispLcdColor( 0, y, 1, TFT_WHITE, "Now" ); dispLcdColor( x, y, 2, COLOR_TEMPERATURE, "T:" ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, fg_t, "%5.2lf", temperature ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_HUMIDITY, " H:" ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, fg_h, "%5.2lf", humidity ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_PRESSURE, " P:" ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, fg_p, "%7.2lf", pressure ); /* サ綛喝*/ y = 170; dispLcdColor( 0, y, 1, TFT_WHITE, "Avg" ); dispLcdColor( x, y, 2, COLOR_TEMPERATURE, "T:" ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, "%5.2lf", temperature_prev ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_HUMIDITY, " H:" ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, "%5.2lf", humidity_prev ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_PRESSURE, " P:" ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, "%7.2lf", pressure_prev ); if ( setGraphDataInterval( temperature, humidity, pressure )) { drawGraphAll(); } /* 蕭篏茵腓削取;腓差禺禮祟蘂PRS腮礫禊絆蜿 */ #if !defined( USE_APRS ) bg_t_max = bg_t_min = bg_p_max = bg_p_min = bg_h_max = bg_h_min = TFT_BLACK; if ( temperature_max < temperature ) { temperature_max = temperature; bg_t_max = TFT_RED; } if ( temperature_min > temperature ) { temperature_min = temperature; bg_t_min = TFT_BLUE; } if ( humidity_max < humidity ) { humidity_max = humidity; bg_h_max = TFT_RED; } if ( humidity_min > humidity ) { humidity_min = humidity; bg_h_min = TFT_BLUE; } if ( pressure_max < pressure ) { pressure_max = pressure; bg_p_max = TFT_RED; } if ( pressure_min > pressure ) { pressure_min = pressure; bg_p_min = TFT_BLUE; } y = 200; dispLcdColor( 0, y, 1, TFT_WHITE, "Min" ); dispLcdColor( x, y, 2, COLOR_TEMPERATURE, "T:" ); dispLcdColorBg( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, bg_t_max, "%5.2lf", temperature_max ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_HUMIDITY, " H:" ); dispLcdColorBg( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, bg_h_max, "%5.2lf", humidity_max ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_PRESSURE, " P:" ); dispLcdColorBg( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, bg_p_max, "%7.2lf", pressure_max ); y += 17; dispLcdColor( 0, y, 1, TFT_WHITE, "Max" ); dispLcdColor( x, y, 2, COLOR_TEMPERATURE, "T:" ); dispLcdColorBg( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, bg_t_min, "%5.2lf", temperature_min ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_HUMIDITY, " H:" ); dispLcdColorBg( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, bg_h_min, "%5.2lf", humidity_min ); dispLcdColor( M5.Lcd.getCursorX(), y, 2, COLOR_PRESSURE, " P:" ); dispLcdColorBg( M5.Lcd.getCursorX(), y, 2, TFT_WHITE, bg_p_min, "%7.2lf", pressure_min ); if ( 0 ) { temperature_prev = temperature; humidity_prev = humidity; pressure_prev = pressure; } #endif #endif #if defined( USE_LCD ) //dispLcdColor( 0, 0, 1, WHITE, "T:%s", temp_c ); //dispLcdColor( 0, 16, 1, WHITE, "H:%s", hum_c ); //dispLcdColor( 64, 8, 1, WHITE, "P:%s", pres_c ); dispLcdColor( 0, 0, 1, WHITE, "%5.2lf %5.2lf %7.2lf", temperature, humidity, pressure ); #if defined( USE_ANALOG ) int n, i; n = sizeof( analog_gpio ) / sizeof( int ); for ( i = 0 ; i < n ; i++ ) { dispLcdColor( i * 30 , 10, 1, WHITE, "%4d ", analogRead( analog_gpio[i] )); } #endif #endif } // // 違 // #define GRAPH_X 0 #define GRAPH_Y 40 #define GRAPH_WIDTH 320 #define GRAPH_HEIGHT 100 #define GRAPH_SEED 3 #define GRAPH_DATA_MAX (GRAPH_WIDTH-2) #define GRAPH_INTERVAL 5 #define SEED_TEMPERATURE 0 #define SEED_HUMIDITY 1 #define SEED_PRESSURE 2 void initGraph() { #if defined( USE_M5STACK ) M5.Lcd.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT, BLACK ); M5.Lcd.drawRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT, WHITE ); #endif } void clearGraph() { #if defined( USE_M5STACK ) M5.Lcd.fillRect( GRAPH_X + 1, GRAPH_Y + 1, GRAPH_WIDTH - 2, GRAPH_HEIGHT - 2, BLACK ); #endif } double graphData[GRAPH_DATA_MAX][GRAPH_SEED]; uint16_t graphDataN = 0; /* 筝絎с若帥篆絖 篆絖翫 true, ∴鐚鐚經 false菴 */ bool setGraphDataInterval( double temperature, double humidity, double pressure ) { static time_t nextTime = 0L; if ( nextTime > now()) return false; nextTime = now() + GRAPH_INTERVAL; // 違祟羯 setGraphData( temperature, humidity, pressure ); return true; } void setGraphData( double temperature, double humidity, double pressure ) { if ( graphDataN < GRAPH_DATA_MAX ) { } else { int i, j; for ( i = 0 ; i < GRAPH_DATA_MAX - 1; i++ ) { for ( j = 0; j < GRAPH_SEED; j++ ) { graphData[i][j] = graphData[i + 1][j]; } } graphDataN--; } //Serial.println( graphDataN ); graphData[graphDataN][SEED_TEMPERATURE] = temperature; graphData[graphDataN][SEED_HUMIDITY] = humidity; graphData[graphDataN][SEED_PRESSURE] = pressure; graphDataN++; } void drawGraphAll() { clearGraph(); drawGraph( SEED_TEMPERATURE, COLOR_TEMPERATURE ); drawGraph( SEED_HUMIDITY, COLOR_HUMIDITY ); drawGraph( SEED_PRESSURE, COLOR_PRESSURE ); } void drawGraph(uint16_t seed, uint16_t color) { double max = -10000.0; double min = 10000.0; int x, y; for ( x = 0; x < graphDataN; x++ ) { if ( max < graphData[x][seed] ) max = graphData[x][seed]; if ( min > graphData[x][seed] ) min = graphData[x][seed]; } if ( max == min ) { max += 0.5; min -= 0.5; } else { max += 0.1; min -= 0.1; } for ( x = 0 ; x < graphDataN; x++ ) { y = GRAPH_Y + GRAPH_HEIGHT - ((graphData[x][seed] - min) / (max - min ) * GRAPH_HEIGHT); //Serial.print( y ); Serial.print( "," ); #if defined( USE_M5STACK ) M5.Lcd.drawPixel( x + 1, y, color ); #endif } //Serial.println( "" ); } #endif // // Morse LED // #ifdef USE_MORSE_LED void statusMorse() { double temperature, pressure, humidity; char buf[256]; readThp(&temperature, &pressure, &humidity); sprintf( buf, "T %.0f H %2d P %d", temperature, (int)humidity, (int)pressure ); setMorse( buf ); } void doMorseLed() { if ( morse_led == 0 ) return; execMorseFromQue(); } // // Todo: 篁ヤ磧祚礬禮 // #define MORSE_QUE_MAX 10 int morse_que_n = 0; char * morse_que[ MORSE_QUE_MAX ]; void setMorse( const char * str ) { // Serial.printf( "setMorse(): %s Length=%d Que=%d\n", str, strlen( str ), morse_que_n ); char * p; if ( morse_que_n >= MORSE_QUE_MAX ) { Serial.println( "Error: too many morse_que in setMorse()" ); return; } if ( (p = (char *)malloc( strlen( str ) + 1 )) == NULL ) { Serial.println( "Can't allocate memory in setMorse()" ); return; } // Serial.printf( "address is %ld\n", p ); memcpy( p, str, strlen( str ) + 1 ); morse_que[morse_que_n] = p; morse_que_n++; } int getMorseQueN() { return morse_que_n; } void execMorseFromQue() { static boolean exec = false; int q; if ( exec != false ) return; if ( morse_que_n == 0 ) return; exec = true; // Serial.printf( "execMorseFromQue(): start\n" ); Serial.printf( "MORSE: %s\n", morse_que[0] ); ledMorse( morse_que[0]); free( morse_que[0] ); for ( q = 0 ; q < morse_que_n - 1 ; q++ ) { morse_que[q] = morse_que[q + 1]; } exec = false; morse_que_n--; // Serial.printf( "execMorseFromQue(): done\n" ); } // // // void ledMorse( char * str ) { int n, i; n = strlen( str ); for ( i = 0 ; i < n ; i++ ) { ledMorseChar( str[i] ); } } const char * morse_code[] = { "_______", "", "", "", "", "", "", "", "", "", "", "", "", "", "010101" /* or "010". */, "", /* !-/ 32 to 47 */ "11111", "01111", "00111", "00011", "00001", "00000", "10000", "11000", "11100", "11110", // 0-9 // "1", "01", "001", "0001", "00001", "00000", "10000", "1000", "100", "10", // 0-9 ュ "", "", "", "", "", "", "", // :;<=>?@ "01", "1000", "1010", "100", "0", "0010", "110", "0000", "00", "0111", "101", "0100", "11", // A-M "10", "111", "0110", "1101", "010", "000", "1", "001", "0001", "011", "1001", "1011", "1100", // N-Z }; void ledMorseChar( char c ) { int n, i; int code = c - ' '; char s; /* Serial.printf( "sizeof(morse_code ) is %d\n", sizeof( morse_code ) / sizeof( char * )); return; */ if ( code < 0 || code > sizeof( morse_code ) / sizeof( char * )) { Serial.printf( "Warning: Illegal Morse Char code, code is %d, %c\n", c, c ); return; } // Serial.println( code ); n = strlen( morse_code[code] ); // Serial.println( n ); //Serial.printf( "MORSE: %c %s\n", c, morse_code[code] ); for ( i = 0 ; i < n ; i++ ) { switch ( morse_code[code][i] ) { case '1': // Serial.print( "L" ); digitalWrite( morse_led, HIGH ); delay( morse_speed * 3 ); digitalWrite( morse_led, LOW ); delay( morse_speed * 1 ); break; case '0': // Serial.print( "S" ); digitalWrite( morse_led, HIGH ); delay( morse_speed * 1 ); digitalWrite( morse_led, LOW ); delay( morse_speed * 1 ); break; case '_': delay( morse_speed * 1 ); break; } // delay( morse_speed * 3 ); } //Serial.println(); delay( morse_speed * 3 ); } #endif #if defined( USE_OTA ) // ref. sample sketch BasicOTA.ino void initOta() { ArduinoOTA .onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem"; // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() Serial.println("Start updating " + type); }) .onEnd([]() { Serial.println("\nEnd"); }) .onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println( "OTA Enabled" ); } #endif