Which wireless board?

Hi.
I would like to make my UNO powered weather station, wireless, and able to upload the data to Wunderground via my desktop pc, as usual there seems to be choices, of which searching for relevant info seems impossible, what I would like to know from those of you already informed, should I use ESP8266 or NRF24L01 platforms.

Ray

If you use the ESP, you can lose the UNO. :sunglasses:

Hello
Take a view here.

If you need WiFi, start with a board that already has WiFi.
Replace the Uno with a Wemos D1 Mini.
If you use the MQTT protocol you can send the data straight into the PC.

why would I lose the UNO?

Hi. I am still learning Arduino, maybe this will be a step too far too quick? My weather station will be no more than 5 meters away from my desktop.

Hi. I am still learning Arduino, so if I'm use the MQTT protocol (I will have to look this up) I can upload to the internet, like Wonderground Weather ??

An ESP32 can do all the weather station readings as well as transmit the data.

My weather station code using MQTT and a ESP32:

/*
   Project, use solar cells to generate power
   2/2/2020

*/
#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include <ESP32Time.h>
////
#define evtDoMQTTwd          ( 1 << 1 )
EventGroupHandle_t eg; // variable for the event group handle
////
WiFiClient   wifiClient;
PubSubClient MQTTclient(mqtt_server, mqtt_port, wifiClient);
ESP32Time    rtc;
//////
Adafruit_BME680 bme( GPIO_NUM_5 );
///
/*
   This semaphore is used to stop or prevent a publish from happening during client.loop()
*/
SemaphoreHandle_t sema_MQTT_KeepAlive;
SemaphoreHandle_t sema_mqttOK; // protects the int mqttOK
////
QueueHandle_t xQ_Message; // payload and topic queue of MQTT payload and topic
const int     payloadSize = 300;
bool          TimeSet = false;
struct        stu_message
{
  char        payload [payloadSize] = {'\0'};
  String      topic ;
} x_message;
////
int mqttOK = 0; // stores a count value that is used to cause an esp reset
////
void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
  // clear locations
  memset( x_message.payload, '\0', payloadSize );
  x_message.topic = ""; //clear string buffer
  x_message.topic = topic;
  int i = 0;
  for ( i; i < length; i++)
  {
    x_message.payload[i] = ((char)payload[i]);
  }
  x_message.payload[i] = '\0';
  xQueueOverwrite( xQ_Message, (void *) &x_message );// send data to queue
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
////
// interrupt service routine for WiFi events put into IRAM
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case SYSTEM_EVENT_STA_CONNECTED:
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      log_i("Disconnected from WiFi access point");
      break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
      log_i("WiFi client disconnected");
      break;
    default: break;
  }
} // void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
////
////
void setup()
{
  x_message.topic.reserve( payloadSize );
  xQ_Message  = xQueueCreate( 1, sizeof(stu_message) );
  sema_mqttOK = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_mqttOK );
  eg = xEventGroupCreate(); // get an event group handle
  xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 20000, NULL, 5, NULL, 1 );
  xTaskCreatePinnedToCore( fDoBME, "fDoBME", 20000, NULL, 3, NULL, 1 ); // assigned to core
  xTaskCreatePinnedToCore( fparseMQTT, "fparseMQTT", 10000, NULL, 4, NULL, 1 ); // assign all to core 1, WiFi in use.
  xTaskCreatePinnedToCore( fmqttWatchDog, "fmqttWatchDog", 3000, NULL, 3, NULL, 1 ); // assign all to core 1
} //void setup()
////
////
void fmqttWatchDog( void * paramater )
{
  int UpdateImeTrigger = 86400; //seconds in a day
  int UpdateTimeInterval = 85000; // get another reading when = UpdateTimeTrigger
  int maxNonMQTTresponse = 3;
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 60000; //delay for mS
  for (;;)
  {
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    xSemaphoreTake( sema_mqttOK, portMAX_DELAY ); // update mqttOK
    mqttOK++;
    xSemaphoreGive( sema_mqttOK );
    if ( mqttOK >= maxNonMQTTresponse )
    {
      log_i( "mqtt watchdog rest" );
      vTaskDelay( 200 );
      ESP.restart();
    }
    UpdateTimeInterval++; // trigger new time get
    if ( UpdateTimeInterval >= UpdateImeTrigger )
    {
      TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
      UpdateTimeInterval = 0;
    }
  }
  vTaskDelete( NULL );
} //void fmqttWatchDog( void * paramater )
////
void connectToMQTT()
{
  MQTTclient.setKeepAlive( 90 ); // needs be made before connecting
  byte mac[5];
  WiFi.macAddress(mac); // get mac address
  String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
  while ( !MQTTclient.connected() )
  {
    // boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
    MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password, NULL , 1, true, NULL );
    vTaskDelay( 250 );
  }
  MQTTclient.setCallback( mqttCallback );
  MQTTclient.subscribe( topicOK );
  log_i("MQTT Connected");
} // void connectToMQTT()
////
void fDoBME ( void *pvParameters )
{
  if (!bme.begin()) {
    log_i("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }
  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
  TickType_t xLastWakeTime    = xTaskGetTickCount();
  const TickType_t xFrequency = 1000 * 15;
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  String bmeInfo = "";
  bmeInfo.reserve( 100 );
  int Count = 0;
  for ( ;; )
  {
    bmeInfo.concat( String((bme.readTemperature() * 1.8f) + 32.0f, 4) ); // (Celsius x 1.8) + 32
    bmeInfo.concat( "," );
    bmeInfo.concat( String( bme.readPressure() / 133.3223684f,4) ); //mmHg
    bmeInfo.concat( "," );
    bmeInfo.concat( String(bme.readHumidity(),3) );
    bmeInfo.concat( "," );
    bmeInfo.concat( String(bme.readGas()) );
    xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
    MQTTclient.publish( topicOutside, bmeInfo.c_str() );
    xSemaphoreGive( sema_MQTT_KeepAlive );
    xEventGroupSetBits( eg, evtDoMQTTwd );
    Count++;
    log_i( "Tick from line 142 count is %d", Count );
    bmeInfo = ""; 
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  } // for loop
  vTaskDelete ( NULL );
} // void fDoBME ( void *pvParameters )
////
/*
    Important to not set vTaskDelay to less then 10. Errors begin to develop with the MQTT and network connection.
    makes the initial wifi/mqtt connection and works to keeps those connections open.
*/
void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  // setting must be set before a mqtt connection is made
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 250 ); //task runs approx every 250 mS
  }
  vTaskDelete ( NULL );
}
////
void connectToWiFi()
{
  int TryCount = 0;
  //log_i( "connect to wifi" );
  while ( WiFi.status() != WL_CONNECTED )
  {
    TryCount++;
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    vTaskDelay( 4000 );
    if ( TryCount == 10 )
    {
      ESP.restart();
    }
  }
  WiFi.onEvent( WiFiEvent );
} // void connectToWiFi()
////
void fparseMQTT( void *pvParameters )
{
  struct stu_message px_message;
  for (;;)
  {
    if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
    {
      xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
      mqttOK = 0;
      xSemaphoreGive( sema_mqttOK );
      if ( !TimeSet)
      {
        if ( String(px_message.topic) == topicOK )
        {
          String temp = "";
          temp        = px_message.payload[0];
          temp        += px_message.payload[1];
          temp        += px_message.payload[2];
          temp        += px_message.payload[3];
          int year    =  temp.toInt();
          temp        = "";
          temp        = px_message.payload[5];
          temp        += px_message.payload[6];
          int month   =  temp.toInt();
          temp        = "";
          temp        = px_message.payload[8];
          temp        += px_message.payload[9];
          int day     =  temp.toInt();
          temp        = "";
          temp        = px_message.payload[11];
          temp        += px_message.payload[12];
          int hour    =  temp.toInt();
          temp        = "";
          temp        = px_message.payload[14];
          temp        += px_message.payload[15];
          int min     =  temp.toInt();
          rtc.setTime( 0, min, hour, day, month, year );
          log_i( "%s   rtc  %s ", px_message.payload, rtc.getTime() );
          TimeSet     = true;
        }
      }
    }
  } //for(;;)
  vTaskDelete( NULL );
} // void fparseMQTT( void *pvParameters )
////
void loop() {}
////

Don't see why not. If you don't need the data local, why not simply upload the data directly from the Wemos to WU? Skip the PC.

Idahowalker's code is very advanced, but it does demonstrate what you can do with a Wemos D1 and MQTT.

You can see that there are several routes to your goal. Start simple. Get a Wemos D1 Mini (they are cheap, buy five) and experiment with publishing (MQTT-speak for sending) "Hello World" and subscribing (MQTT-speak for receiving) to the topic on the PC. You will grok.

I have several spare BME280 boards, will they do?

The BME 280 can measure Temperature, Humidity, and Air Pressure if that is good enough for you then it is good enough, right?

Because if you have an ESP, you don't need a UNO to complicate matters.

I am very pleased with the performance of the HC12's I have used, but you want to make an effort to get "genuine" HC12 modules. Some of the clones have poor range and crystal frequency issues.
https://www.thebackshed.com/forum/ViewTopic.php?TID=10443
https://forum.arduino.cc/t/hc-12-genuine-or-non-genuine/520516

The UNO. Is a microcontroller. It has 6 to 8 analog inputs and over a dozen digital I/O

It has no built in radio or wifi.

The ESP8266 has 1 analog and about 10 digital I/O

The Esp32 ups that to over 8 analog and depending of board as many as 30 total I/O analog and digital combined.

The ESP32 also has bluetooth.
Again depending on model.

All share the basic codes
The BME280 works the same on all of them.

NODE RED is a couple extra layers of complexity. Not a beginners platform.

Esp32 offers more features deep sleep and onboard datalogging

Start with A BEGINNERS GUIDE TO THE ESP8266.

It will walk you through most of what you will need.
And it does carry over to the ESP32

Hi all, many thanks for your help and guidance.

Ray

So it's down to Wemos D1 or ESP 32, in your considered opinion which one to choose, which will be the easiest for me to do? as I say, I am at the novice stage with Arduino Uno. secondly, while googling it appears there are several manufacturers of the ESP 32 board, whose should I go with? who's to avoid?

Note strictly that it is the WeMOS D1 Mini, not the "WeMOS D1" which is a larger board in the basically impractical Duemilanove (UNO) format.

I stick with ESP32 developer boards made by HiLetGo. I have tested out over 80% of the ESP32 API on the HiLetGo developer boards and so far HiLetGo closely follows the ESP32's API.

My go-to board is the Wemos D1 Mini. They are cheap enough ($5 each) that I buy them ten at a time from Banggood. When I get down to two boards, I buy another ten. This way I always have a few on hand even considering the month-long delay in U.S. Customs.

I would wager that there are far, far more people here using the D1 Mini than the more expensive ESP32. And the ESP32 comes on a wild array of different boards that are not all pin compatible.

I would start with the D1 Mini because everything you do on the Mini can be ported to the ESP32 later if you need the additional analog or digital ports. Even then, I just add a port expander chip to the D1 Mini.

1 Like

One of the most fundamental things that the creators of the arduino did was the Standardize the boards.

Expressif lost any semblance of control and makers have run amuck.
There are a few houses have a decent product that could be considdered a reliable design. By that i mean the board you get next month will be the same as the board last month.

TTGO and MH-ET are such makers.

If you go ESP8266 due to the low cost you get wifi. Wemos D1 mini is the defacto standard and clones abound.

The ESP32 requires two protoboards due to its wide footprint.

Or use lots of duPont cables.

I use a lot of the Wemos D1 minis and a plethora of ESP32.
I like the "jeep carrier" style. One row if pins down each side but shorter than the long "fleet carrier" style.

Check for a breakout board that has a long narrow set of pins that allows you to plug into a protoboard

Ps: i gave stevemanns post a like. I too would start with and personally use the Wemos D1 mini as my go to board