text:
Can I change Arduino program on-the-fly?
I have Arduino which is programmed to do something. Is it possible that I could allow it to change behaviour by changing program on-the-fly without the need to reprogram Arduino via the computer.
What I need is to send the message via MQTT which will Arduino receive and change its behaviour by it. I managed to change the frequency of messages published or to add some new data, but what if I want to change how decisions are made. What if I want to change some Arduino code, to add some if or another state, can that be done on the fly?
Update: Changing device behaviour on the fly or after restart is acceptable. I am not strict with using arduino, nodemcu is and option. I just need a way to add new functionality to device if I need.

But that is using Arduino IDE, isn't it? Is it possible to change some code without need to reprogram it?

Your code in stored in flash memory. Your code can't change the content of the flash memory. You must understand Arduino is NOT a computer. On a computer (Von Neumann architecture) we store code and data in RAM and we can change content of RAM. So a code can change itseof on the fly. Arduino has an Harvard architecture: code is in one memory, data inside another memory. Not possible for code to perform "self modification". On the other side you can have a code using a "script" and yuo can update this script (in RAM or EEPROM)

@Peter - you are mistaken.  Harvard architecture machines are very much "computers" as well.  The arduino is most definitely a "computer".  Additionally, although by no means a requirement for being a "computer", the Arduino can alter its own flash, though the process is a bit tricky, and one shouldn't design a scheme to do it repeatedly on an ongoing basis or the flash will wear out.

@Peter suggested: “you can have a code using a ‘script’”. I second that suggestion. See Interpreted Languages on Arduino playground.

@Chris Stratton  The fact of talking about Harvard had the main purpose of giving a better view of the problem. I played a lot with ASM and Self-modifying code (in the 80') and I see many people struggling, at basic level, with memory problem on the Arduino, because they think of it as a "small computer" when in fact, the principle is different. I agree we can have Harvard or Von Neumann computer, of course :) Cheers.

@Peter well, the fact that there is a bootloader able to reprogram the Arduino without an external programmer may tell you that the AVR is indeed capable of writing on its own flash ;)

@emir can you just clarify if you need the arduino to reprogram it "runtime", so without resetting, or just like you'd do if you connected to the USB port (but through the net)? If the former than the suggestion is to change the logic of the algorithm like JRobert suggests in his answer; if the latter, you can modify the bootloader to accept data from the network connection, then when you want to flash you have to reset the board and then connect to the bootloader (not so easy, but doable)

@frarugi87 restarting device is no problem. It would work in any way

@emir then it is possible, even if it is rather difficult. You will have to modify the bootloader so that it gets the program somewhere (e.g. a direct TCP connection). Note that the bootloader has a very limited space available. Then from the application when you receive the MQTT request you save a flag in eeprom and then reset the board; in the bootloader if the flag is present download the FW and write it in the flash, then clear the flag and reboot. When the flag is not present, launch the application. Even if... Again, if you can do what JRobert suggests it is MUCH better

@farugi87. Every thing is possible. But I think we must clarify a point: some tips and tricks are possible and can be used in coding party. But using them in real app is not the same story. ;)

Replacing or modifying the existing code during run-time will require some form of uploading and over-writing the old code. This is deliberately not made straightforward or easy for these kinds of micro-controllers.
But you can change the program's strategy on the fly, if you anticipate the potential changes and include the code for each of the possibilities.
For example, write a set of functions that each embody one of the various ways of operating, and, at run-time, select which function the program should use. You can change the selection by setting a value from the keyboard or the program could sense some external trigger such as a button-press, or a temperature reading and respond by changing the selection - the value of an int, perhaps. A switch statement can use that value to call the appropriate function at the appropriate time:
uint8_t strategy = 0;           // init to the default strategy

switch( selector ){
case(1):                // has event 1 happened?
   func1();
   break;

case(2):                // has event 2 happened?
   func2();
   break;

case(3):                // has event 3 happened?
   func3();
   break;

default:                // none of the above or undefined selector value
   funcDefault();
   break;
}

This does mean that all of the code for the possible operating strategies must be included at upload-time and share the program-memory space, but unless your job is very complex, even an Uno should be capable enough.
Update:

I need to be able to update the device with some new functionality.

There is another approach which may or may not fit in an Uno but would be doable with a Mega 2560 or other larger-RAMmed machine: interpreted code.

Define a set of operations that includes whatever you'll need to operate your external device(s): the necessary I/O operations to read your sensors and control your hardware; to make logical and/or arithmetic tests and conditionally branch or call a function based on the test result; to listen for a user-signal from the terminal (for example) and return to the arduino program. This will be the "language" in which you write your control program.
Define a concise coding scheme to specify each operation and whatever data it needs, such as reading a temperature sensor and storing the result in a named place. If your control programs won't be too complex, you can get away with pre-defining A, B, ..., Z to be data registers of some appropriate type.
In C++, write an interpreter for this new language. It's program will consist of the codes you just defined. But this code will be seen as data by the interpreter. This is the key - this pseudo-code will live in RAM, where your interpreter - a collection of C++ functions - can read and execute it, and the Arduino program can download a new one, over-write the old one, and run the interpreter again.

Caveat: Like the Greek mythological Hydra, this is a job that can grow new challenges as you address the current ones, but it is doable if you keep it simple as possible and include only what you must have to make it work.
Run-time-interpreted code can take 10 - 50 times as long to execute as a natively coded application, so anything that can be pre-coded in C++ should be. The finer and more flexible your interpreted instructions, the more expressive you can be when writing the control program, but the interpreter will be more complex to write, slower to execute, and harder to debug. Design your language to be only as flexible as it must be to allow you to write new control algorithms.
If you try to invent an entire pseudo-computer, completely flexible and capable of being programmed for any and all purposes, you'll drive yourself crazy. Whole businesses have folded after sinking money and time into inventing a new and better computer and got so bogged down they couldn't recover. Don't go that route.
Start with the grossest, least flexible operations you can live with and get that much working. Discover its limitations and address those, and only those, one at a time, until you have a sufficiently flexible system in which to control your device.

I am aware of this approach, but this would require knowing in advance about what device could do. I need to be able to update the device with some new functionality.

Code that writes to flash has to reside in the bootloader section.
The only way I know how to execute code in the bootloader section is
after a reset. However, even if you could transfer execution to the bootloader section and get something to work, it would
have to contend with the fact that flash has limited write cycles and
will reduce the life of the device. Possibly to the point of being
useless for a practical application.
Executing code from RAM. Self explanatory, modify code all you want.
There is an application note for AVR that discusses this.
Write an interpreter for your needs. yuk!

EDIT: There is some GCC code example here.

You should be able to jump to locations in the bootloader section provided that you know the assumptions of the code you placed there.  You can also do a soft reset.  But yes, the flash endurance is an issue.

I was not aware of limitation with a number of flashing. Do you refer to firmware flashing or updating a device with code using IDE or over OTA?

Write/Erase Cycles: 10,000 Flash/100,000 EEPROM

The claim about "executing code from RAM" is erronous.  That is not supported on an AVR, your link is to a document for an Atmel SAM-series ARM processor, not an AVR.

Sorry. Wrong application note. I was wondering why I wrote AVR. It came from this application note for AVR32825: Executing code from external
SDRAM Specifically for the AVR 32 UC3A and UC3C series.

You can change the behaviour of Arduino on-the-fly but it's not necessary to reprogram, just design your code to change behaviour with some variables you get form outsite e.g. a server, but this new changes must be defined previously in your code.
If you have a list of states and want to add more, use a dynamic array or use an array with enough space and when send a MQTT message that Arduino parses adding tha new state or even deleting a state.

I need to see how I can update the device with new functionality which was not previously planned.

Is it possible that I could allow it to change behaviour by changing program on-the-fly without the need to reprogram Arduino via the computer.

(emphasis added by me).
As some answers pointed out, you can change the behaviour if you allow for it in advance. For example, store in EEPROM some setting (like how often something happens) and have a method of changing that setting.

Different bootloader
However if you want to change the behaviour completely then you need to upload new code (whether the code is in RAM or program memory doesn't really change this part).
The bootloader installed as a standard on the Arduinos allows for code to be uploaded via a protocol which arrives at the serial port shortly after reset. There is nothing to stop you writing your own protocol (eg. using MQTT) and make your own bootloader which uses that - assuming it is small enough to fit into bootloader space (the largest bootloader the Atmega328P can hold is 4096 bytes).

Stand-alone programmer
Since you asked about uploading new code without needing to have the computer, an alternative is to program it in the field using a stand-alone programmer. There are various ones around, including one developed by user Crossroads from the Arduino Forum:

I wrote the code for that one. The basic approach is to write your new code using the IDE (something you would have to do anyway) and then copy the .hex file to a SD or micro-SD card which is then inserted into the programmer as you can see in the photo. The programmer then connects to the target board via a ICSP interface using a 6-core cable as shown. This reprograms the target in about a second. This makes it practical to reprogram a device "in the field" without having to return it to your base, or carry a laptop around with you.

What you need is not a “one trick pony” (arduino) but an actual “horse” - Raspberry Pi. You have no reason not to such as:

Price - RPi Zero - $10
Size - ditto -about the size of a Nano
Functionality::
Pi . . . . . . . . . . . . . . . .  Arduino

wifi           . . . . . . . . . . . . . . . .  no (wifly /Zigbee now you violate #2)
bluetooth   . . . . . . . . . . . . . . . .  no
web server . . . . . . . . . . . . . . . .  no
mysql database . . . . . . . . . . . ..  no
any linux multithreaded
  apps. . . . . . . .. . . . . . . . . . . . .  no
etc etc etc
Did i miss anything? being a technology architect begins with knowing what hardware and software to apply in any given situation. I. E. avoid square pegs in round holes.

You forgot to mention the RPi Zero won't work without a good quality 4 to 8GB micro SD card for storage (OS, libraries and user programs). You also need a "USB OTG Cable", a 1 amp power supply with Micro USB connector, and if you want to connect it using HDMI, there an adapter required for that too. It would cost me $51.46 CDN plus $5 to $10 for shipping, just to get started with the RPi Zero.

Another thing to consider, is whether or not your project needs WiFi, and Bluetooth, and a web server, and MySQL. Why pay for all of this "horse power" if you're not going to use it. The RPi Zero is a computer, and needs to be treated as such. If the power drops on the Arduino, you won’t end up with a corrupt operating system or other software errors: it will just start running code when it’s plugged back in. For Raspberry Pi, you must shut it down within the operating system like any other computer, or else risk corruption and software problems.


text:
Why these specific voltage divider resisters needed for Arduino Uno RX TX pins?
I have an Arduino Uno attached to a Parallax Boe-Bot shield, and plugged into the shield breadboard, the Parallax WX ESP8266 Wi-Fi SIP.
When I attach the DO/DI pins of the ESP8266 board to the RX/TX pins of the Uno, it does not work without a very narrow range of resisters in a voltage divider configuration. I'm trying to learn more about electronics and I would like to know, why these specific values in this specific case?
The DI/DO pins of the SIP are documented as "SIP - output high (set by Vin voltage, either 3.3 or 5.0 V), low 0 V. Input high >Vin/2, input low

When I attach the Parallax shield 5V to the SIP Vin, and the DO to a 220 resister to RX, and also DO to a 1K resister to ground, and DI to 220 to TX and also DI to 1K to ground, serial communications works fine.
If I use the shield 3.3V to SIP Vin, it does not work.
If instead of 220 / 1K, I use 470 / 2K, or 4.7K / 10K, for example, it doesn't work.
If I only set up the voltage divider on the RX pin, it doesn't work.
However, if instead, with either 5V or 3.3V to the SIP Vin, and no resisters, I can run the Uno TX direct to the SIP DI, and the SIP DO to a digital pin, and run that digital pin with SoftwareSerial, for example.
I can run both DI and DO directly with SoftwareSerial, and either 5V or 3.3V to supply Vin.
It's only when I want to connect DO/DI direct to use the Uno's UART (because I don't want serial-driving interrupts to interfere with servo pulses) that I have to carefully select these resisters (through trial and error) and be sure to power with the 5V. Some combinations get communication with errors, but just these specific values (out of the resisters I happen to have on hand) work.
I understand that it is something to do with 3.3V vs TTL serial, but I would like the details. (I will be picking up a logic level converter to try in place of the voltage divider.)
EDIT:
By "not working" -- in all but two cases, with fresh batteries, the SIP seems to get data from the Uno TX, and the DO lamp on the SIP flashes, but Serial.read() sees nothing on the Uno regardless of configured rates. In one of the two cases (I can't recall which) unintelligible, incomplete data is read on the RX pin, and in the last, good case -- where both pins have voltage dividers and the SIP is powered by the 5V line of the Arduino shield (for the Boe-bot) -- with those specific resister values -- the data from the SIP DO is received on the Serial, from pin RX.

A schematic would be in order here. Your question is a bit vague with a few alternative configurations and voltages. Please post a specific configuration that is causing you problems.

I'll add some diagrams.

The output of a voltage divider is:
Vout = Vin * R2 / (R1 + R2)
Where R2 is the resistor in your case which is connected to ground.
See: Sparkfun - voltage dividers
Now in your example of 220 / 1k you have a multiplier of:
Vout = Vin * 1000 /1220 = Vin * 0.82

If both boards are running at 5V you don't need the voltage divider at all, but if you do use it the output would be:
Vout = 5 * 0.82 = 4.1

Now the Atmega328P chip on the Uno has the electrical characteristics defined in the datasheet, amongst others is that a digital pin high has to have a minimum of 0.6 * Vcc (if Vcc is in the range 2.4V to 5.5V)
So if Vcc is 5V (which it is on the Uno) you have to have 0.6 * 5 (that is, 3V) as the minimum for it to be recognised as high.
So, using the voltage divider of 220/1k you have a high still being 4.1V which is in the range 3 to 5V.
However if you have the board set to 3.3V then the output of the voltage divider will be 3.3 * 0.82 = 2.76V which is too low to be recognized as high.
For sending serial from a 3.3V board to a 5V board, simply omit the voltage divider, and then the 3.3V (for high) is in range (it has to be 3+ volts).
However for sending from a 5V board to a 3.3V board you do need a voltage divider (or level shifter) because 5V is too much for a 3.3V board. You can use a voltage divider calculator to simplify the maths.
Something like 1k/1.8k would be about right.
Vout = 5 * 1800 / 2800 = 3.21

According to the documentation for the Parallax WX ESP8266 Wi-Fi Module:

(9) Level shifters and buffers
To ensure maximum compatibility with a wide range of 3.3V and 5V microcontrollers and development boards, the Parallax Wi-Fi module includes voltage level shifters and buffers to ensure that the logic voltage levels at the SIP header are set by the VIN voltage level. If you
  supply 3.3V to VIN, then the IO pins logic voltage level will be 3.3V. If you supply 5V to VIN, then the IO pins logic voltage level will be 5V

I don't see why you need to use a voltage divider or level shifter in the first place.

References

Atmega328P datasheet (32.9 MB)
Sparkfun - voltage dividers
Voltage divider calculator
Another voltage divider calculator
Voltage dividers - Wikipedia

That is what I read elsewhere, but that is not how this hardware combination behaves. Of the combinations I listed, only 220 / 1K works, and only if both are connected (only one divider from DO to RX will not work). 470 / 2K gives 4V and does not work. There must be some other consideration for pins 0 and 1 on the Uno, which happen to be wired to the internal UART. I will pick up a 1.8k resistor and try that, though.

If you look at the Uno reference schematic there is a 1k resistor in series with both D0 and D1 and the UART. However I don't quite see how that would alter your results.

Can you clarify what "does not work"? Sending from the SIP to the Uno? Vice-versa? At what operating voltages?

Also see amended answer regarding the level shifting requirements.

I didn't see that level shifters / buffers note -- thx. By "does not work", the SIP DO/DI LEDs flash, and it appears to get a command, but the Uno does not read any response on Serial. SoftwareSerial reads it fine on another pin. In one case of resisters (I'll have to double check which) Serial gets a read error, but in other cases, nothing is detected.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Locking ATmega328 from reading back the hex file
I want to completely block the access to an ATmega328. How do I do this?
I have Atmel ICE, AVR studio 7 and Arduino.
Bootloader - optiboot_atmega328
Fuses(without lock) - 0x05, 0xDE, 0xFF
Steps I am executing:

Program fresh ATmega328 with bootloader using Atmel Studio.
Burn the fuses as mentioned above.
Go to Arduino and program the code.
Come back to Atmel Studio >> lock bits >> enable no further programming and verification.>> Fuse bits>> disable reset.

Is the above way OK? Or should I add something to the above?
I have programmed the fuse bit with "Further programming and verification disabled". I read out the hex file and it does not match even I programmed the same hex into a different micro and it didn't work. This seems to be fine. But will high Voltage programmer brick this wall?
Note: When I program the above fuse bit. I am unable to disable the RESET or SPI. It says one or more register differ
I want avoid a readback via high voltage programmer too.
I have too many people to steal my code I want to avoid it. Kindly help
Siddharth

Why don't you want to disable SPI?

Locking out programming prevents writing, and locking out verification prevents reading, via all programming methods.
Note that there is no way to prevent erasing the chip, which will clear both the lock bits and the flash.

This is not an answer. But a reply to the abive post. So Further programming and verification disabled.
Will this option do the job??? Siddharth

That will prevent writing to and reading from the flash memory, just as it says in the datasheet.

"Locking" the chip only has any effect when using one of the hardware programming interfaces. Yes, it prevents anyone with a programmer from reading the data from the chip (verify disabled).
However, it does not stop software on the chip itself from reading the contents of the chip. And that includes the bootloader.
Since you use a bootloader it is possible (if implemented in your bootloader, I am not familiar with what is implemented in Optiboot) to use the bootloader to read the contents of the chip through USB.
To properly protect your software you will have to either remove the bootloader and only program through a hardware programmer or ensure that the bootloader has no method to read or otherwise access the flash memory of the chip (intentional or otherwise).

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Connecting to MQTT causes DHT11 Sensor to stop working?
I have a project I am working on, based on an ESP32 from NodeMCU. I have a bunch of sensors connected to said ESP32 - they all work and the code itself "works" with a minor quirk.
The issue in question starts with a DHT11 sensor. I started from the basic "hello world" DHT11 code (you can find it easily with a DHT11 search in google). That sensor works in my code that you can see below - I copied and pasted the sample code, and except for changing variables, did not alter the sample code really at all.
The issue I have is that while the sample code will read accurately on every loop, in my code, it reads from the sensor exactly once the first time the loop runs, and then never again.
I believe I have isolated the issue to this bit of code and the corresponding function it calls (it didn't used to be a function - that was a troubleshooting step):
  if (!client.connected()) {
    reconnectMQ();
  } etc...

By moving this statement and grouping the MQTT messaging to the end, the system runs a full loop with correct readings, exactly once, but after that function is called the DHT11 begins failing to read.
Things I have tried:

 different variable names for temp and humidity (in case "t" and "h" are in use in the MQ library)
     order of operations (made the loop work once)
     changing the reconnectMQ() to a full function and not just a loop in the main loop
     changing the logic of the DHT11 sensor to at least not hang forever trying to read - this meant it got through this part, but with 0 values
     "turning off" MQ - this means that everything works, but obviously is a bit like cutting off your arm for a sprained wrist.
     ENDLESS Google and Stack searches before resorting to this post.

I hate to do this as my project is 200 lines long, but I suspect the full code is needed to see what's possibly happening.
#include <time.h>
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>

//use pin 23 to read temp and humidity
//our sensor is DHT11 type
//creates an instance of DHT sensor
#define DHTPIN 23
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

//Define the analog pins inbound for the Soil Moisture sensors
const int sm1Pin = 33;
const int sm2Pin = 34;
const int sm3Pin = 35;
const int sm4Pin = 32;

const int power = 22;
const int exec = 21;
const int net = 19;

//define the pin for the light level reading
const int light = 36;

//Init MQTT payload arrays
char data0[50];
char data1[50];
char data2[50];

// declare our Wifi and MQTT connections and other constant settings for the network
const char* ssid     = "*******";            // The SSID (name) of the Wi-Fi network you want to connect to
const char* password = "*******";                          // The password of the Wi-Fi network
const char* mqtt_server = "192.168.1.195";                             // The target mqtt server
const char* input_string = "{\"Reporting\":\"GardenUnit1\", ";       // The name of this garden monitor unit
String clientId = "GP1";
int lcount = 0;

// declare our Wifi and MQTT connections
WiFiClient espClient;
PubSubClient client(espClient);

//
// Reconnects to the MQTT message-bus if the connection died, or we're
// not otherwise connected.
//
void reconnectMQ() {

  digitalWrite(net, LOW);  // turn the Blue NET LED Off

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Wifi not connected - configuring");
    setup_wifi();
  } else {
    Serial.println("Wifi Connected - connecting MQTT");
  }

  // Attempt to connect
  Serial.println("Attempting to connect to MQTT Server...");
  while (!client.connected()) {
    if (client.connect(clientId.c_str())) {
      Serial.println("connected to MQTT server");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }

  // Once connected, publish an announcement...
  String payload = String(input_string) + "\"MQTT\":\"Reconnected\"}";
  payload.toCharArray(data1, (payload.length() + 1));
  client.publish("control", data1); //the "control" topic is just for notifications - change to fit your needs

  digitalWrite(net, HIGH);  // turn the Blue NET LED on
  delay(5000);
}

void setup_wifi() {
  delay(10);
  Serial.print("Connecting to ");
  Serial.print(ssid); Serial.println(" ...");

  WiFi.begin(ssid, password);             // Connect to the wifi network

  while (WiFi.status() != WL_CONNECTED) // Wait for the Wi-Fi to connect
    delay(1000);
    Serial.print('.');

  Serial.println('\n');
  Serial.println("Connected!");
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());         // Send the IP address of the ESP32 to the serial port

}

void setup() {
  Serial.begin(9600); // open serial port, set the baud rate as 9600 bps
  // These Options control the precision of the reading, and the voltage reduction capability of the ESP32
  // Attenuation number 3 is 11DB
  analogSetWidth(10);
  analogSetAttenuation((adc_attenuation_t)3);

  // Define the MQTT Server connection settings and then launch the MQTT Connection
  client.setServer(mqtt_server, 1883);

  // Set output and input pins to correct modes
  pinMode (power, OUTPUT);
  pinMode (exec, OUTPUT);
  pinMode (net, OUTPUT);

  //Turn on Green Power light
  digitalWrite (power, HIGH);

  //Connect to the wireless network
  setup_wifi();

  //This call starts the dht11 sensor instance
  dht.begin();
}

void loop() {
  //Turn on RED EXEC light - this means a sample is being taken
  digitalWrite (exec, HIGH);

  //Read DHT11 Temp and Humidity - Humidity is a % and temp is in Celcius
  float hum = dht.readHumidity();
  float temp = dht.readTemperature();
  // Check if any reads failed but insert bogus data so system continues
    if (isnan(hum) || isnan(temp)) {
        Serial.println("Failed to read from DHT sensor!");
        client.publish("garden1", "{\"Error\":\"Humidty/Temp Sensor Offline!\"}");
        hum = 0;
        temp = 0;
    } else {
        // print the result to Terminal
        Serial.print("Humidity: ");
        Serial.print(hum);
        Serial.print(" %\t");
        Serial.print("Temperature: ");
        Serial.print(temp);
        Serial.println(" *C ");
    }

  //Read value and print to serial for S1
  float s1 = analogRead(sm1Pin);
  Serial.print("Sensor 1: ");
  Serial.print(s1);
  Serial.println();
  //Read value and print to serial for S2
  float s2 = analogRead(sm2Pin);
  Serial.print("Sensor 2: ");
  Serial.print(s2);
  Serial.println();
  //Read value and print to serial for S3
  float s3 = analogRead(sm3Pin);
  Serial.print("Sensor 3: ");
  Serial.print(s3);
  Serial.println();
  //Read value and print to serial for S4
  float s4 = analogRead(sm4Pin);
  Serial.print("Sensor 4: ");
  Serial.print(s4);
  Serial.println();

  float L1 = analogRead(light);
  Serial.print("Light level: ");
  Serial.print(L1);
  Serial.println();

  if (!client.connected()) {
    reconnectMQ();
  }

  String payload = String(input_string) + "\"S1\":\"" + s1 + "\", \"S2\":\"" + s2 + "\", \"S3\":\"" + s3 + "\", \"S4\":\"" + s4 + "\"}";
  payload.toCharArray(data0, (payload.length() + 1));
  Serial.println("Publishing message 1:");
  while (!client.publish("garden1", data0)) {
    Serial.print(".");
  }
  String payload2 = String(input_string) + "\"Humidity\":\"" + hum + "\", \"Temperature\":\"" + temp + "\", \"Light\":\"" + L1 + "\"}";
  payload2.toCharArray(data2, (payload2.length() + 1));
  Serial.println("Publishing message 2:");
  while (!client.publish("garden1", data2)){
    Serial.print(".");
  }

  //Turn off RED EXEC light - this means a sample is done
  digitalWrite (exec, LOW);
  lcount = lcount + 1;
  delay(10000);
}

What happens when the code I have here runs is that I see all the messages at the Mosquito server and in serial monitor, and the loop runs as expected. Due to the logic I had to put in to keep the program running, after the first reading from the DHT11, temp and hum come back as 0 forever. This is obviously not what I want.
What is obvious:
Something happens between the first reading of the DHT11 and the next that makes it unhappy.
What is not:
What that something is. That something occurs in the MQTT connection, but for the life of me I cannot figure out what it is or isolate it.
So now I leave it to the community. What the heck is happening here?!

Hint(s): What could make the DHT11 read fail? Assuming 3.3V VDD to DHT11: How large pullup resistor? Extra capacitor on VDD-GND at the sensor? Extra long cables? Checked with logic analyzer?

So normally I would agree with this assessment, and I tried rejiggering the hardware every way I could find online, however, the sensor only errors if the software connects to MSMQ. If I remove all connection code from the program (going back to the simple DHT11 test works fine) then the sensor reads flawlessly for hours on end, wired as is. (3v, direct from the 3v pin on the ESP, on a breadboard, maximum wire length of about 15 CM total roundtrip)
The issue in this case is definitely software as the hardware works flawlessly with different code.

What happens if you try to print hum and temp after this line:
Serial.println("Failed to read from DHT sensor!");

@linhartr22 - I think you might be a genius - I was thinking that when I send the values to MQTT, that these lines:
String payload2 = String(input_string) + "\"Humidity\":\"" + hum + "\", \"Temperature\":\"" + temp + "\", \"Light\":\"" + L1 + "\"}";
  payload2.toCharArray(data2, (payload2.length() + 1));

Might be changing the variable type. Based on the error when I try to print them, I am sure of it.
invalid operands of type 'const char [6] and float to binary operator +
So the question is, what is the declaration to redeclare those variables. TO THE GOOGLE MACHINE!

Turns out that wasn't it. I changed my string method to use sprintf() syntax and it still exhibits the same issue - when it loops back to the "top" of the loop, the red LED comes on as instructed in the code, and then it sits forever, indicating the error is happening on the read of the humidity from the DHT11. I still think this might be the right track, in that the humidity variable is somehow not compatible on the second loop, but the dtostrf() code I added should have remedied that. So I am still at the original issue - with MQTT turned on, DHT11 does not work. Turned off, works great.

This could be a conflict between the DHT11 library and the MQTT library, trying to use the same timer or other resource in the MCU.

I suspect so as well, but that is beyond my ability or desire to fix. I have simply told the ESP to reset after each loop. Incredibly inelegant, but functional.

Leaving this here in case anyone else has a similar issue as an "answer" to my own question:
Simply put - DHT11 library as used, and MQTT library as used conflict. That's it, that's the answer.
There are two options for correcting this depending on your needs:

don't use or deeply examine and rebuild one of the libraries - frankly this was a negative ROI for me and not worth it
Add an  ESP.restart();  at the end of the main program loop and AFTER the sleep timer - this reboots the ESP and allows the DHT11 to read BEFORE the MQTT connection happens and the solution works.

This, in my mind is not "a fix" it is a workaround, but it does address the primary issue.

I think that's not a conflict, you just forgot to subscribe the topic first before sending the data.

No you can see it in the code above - there is no subscribe - it is a publish only. I moved the publish and messaging all over the place in the logical flow and literally it does not matter. The second you publish a message via MQTT, the DHT11 stops reading. The only way to get it to read again is to restart the ESP32.
I do not believe this is a hardware issue, or even a library issue for each library (as they work fine on their own) it is just a conflict in the two libraries. Thus I left this here for others who might experience this.

I've used the DHT11 library, not the DHT library in my sketches. The Example sketch should make it clear what minimal changes you'll need to make to your code.  It always worked well for me.

So I literally used the example code inside my larger program. It is (except for the pin I used, and later the variable names) completely unmodified. You can find the example code here:
http://www.esp32learning.com/code/esp32-and-dht11-sensor-example.php
The issue is not that it doesn't work, it does work, but not in conjunction with MQTT. As soon as my ESP32 connects to the MQ server, the DHT stops reading. No MQTT code, and it works like a charm.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
ESP8266 odd HTTP GET request
I'm using an Arduino Uno to send HTTP requests to my local webserver. To communicate to the ESP8266 I created a SoftwareSerial which is set to a baud rate of 9600.
Whenever I send a HTTP request, the request looks like the following:
    192.168.2.132 - - [22/Dec/2017:12:22:57 +0100] "TP/1.1" 400 173 "-" "-"
    192.168.2.132 - - [22/Dec/2017:12:23:38 +0100] "z\x02BQQA\xBD1.1" 400 173 "-" "-"
    192.168.2.132 - - [22/Dec/2017:12:23:56 +0100] "z\x02BQQA\xBD1.1" 400 173 "-" "-"
    192.168.2.132 - - [22/Dec/2017:12:24:14 +0100] "z\x02BQQA\xBD1.1" 400 173 "-" "-"
    192.168.2.132 - - [22/Dec/2017:12:24:34 +0100] "\xE9\x09BQQA\xBD1.1" 400 173 "-" "-"
    192.168.2.132 - - [22/Dec/2017:12:25:06 +0100] "z\x02BQQA\xBD1.1" 400 173 "-" "-"
    192.168.2.132 - - [22/Dec/2017:12:27:01 +0100] "\x02BQQA\xBD1.1" 400 173 "-" "-"
    192.168.2.132 - - [22/Dec/2017:12:28:11 +0100] "\x02BQQA\xBD1.1" 400 173 "-" "-"

The code to create GET request to send over TCP:
  char *hello = "GET / HTTP/1.1\r\nHost: 192.168.2.106\r\nConnection: close\r\n\r\n";

  if (wifi.send((const uint8_t*)hello, strlen(hello))) {
    Serial.print("Wifi send succesfull\r\n");
  } else {
    Serial.print("Wifi not send succesfully\r\n");
  }

The actual send method:
bool ESP8266::sATCIPSENDSingle(const uint8_t *buffer, uint32_t len)
{
    rx_empty();
    m_puart->print("AT+CIPSEND=");
    m_puart->println(len - 4);

    if (recvFind(">", 5000)) {
        Serial.println("found >");
        rx_empty();

        for (uint32_t i = 0; i <= len; i++) {
            m_puart->write(buffer[i]);
        }

        return recvFind("SEND OK", 30000);
    }
    return false;
}

This line:
m_puart->println(len - 4);

Was in the library actually just m_puart->println(len);
I had to shorten the length of the buffer for esp8266 to wait to, otherwise it wouldn't send the TCP command. The counting part of bytes looks fine to me. Not sure what's causing this behaviour.
The part above is just some extra unusual behaviour but isn't the main priority. So any ideas what's causing the odd HTTP requests?

did you set the 9600 baud rate in the AT firmware?

Yes i did, it's also saved in the flash.


text:
vscode arduino integration errors
I'm just trying to understand how vscode can compile arduino sketch. Now I uploaded some sketch to arduino and it was fine. Now I'm trying to add my own header files to .ino sketch and I got weird faults. I don't understand whats happening. I know this header files in under project.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "chcStandart.h"
#include "chcDefines.h"

When I try to verify my code I get this error:
> c:\Users\Desktop\Main_Code\chc.h:7:25: fatal error: chcStandart.h: No
> such file or directory

Also ı configured my json (c_cpp_prop) file and it looks like that.
"name": "Win32",
            "includePath": [
                "C:\\Program Files (x86)\\Arduino\\tools\\**",
                "C:\\Program Files (x86)\\Arduino\\hardware\\arduino\\avr\\**",
                "C:\\Program Files (x86)\\Arduino\\libraries\\**",
                "C:\\Users\\Musa Ünal\\Documents\\Arduino\\libraries\\",
                "C:\\Users\\Musa Ünal\\Desktop\\Main_Code\\**"

            ],
            "forcedInclude": [
                "C:\\Program Files (x86)\\Arduino\\hardware\\arduino\\avr\\cores\\arduino\\Arduino.h"
            ],
            "intelliSenseMode": "msvc-x64",
            "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.14.26428/bin/Hostx64/x64/cl.exe",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "C_Cpp.intelliSenseEngine": "Tag Parser"

My question is: How I can handle this problem? Thanks!

Where is the file chcStandart.h? The tool is looking for it at c:\Users\Desktop\Main_Code\chcStandart.h

Yes, its under the project, same file with my .ino file

do you have #include "chcStandard.h" or #include <chcStandard.h>  in chc.h?

Ok problem solved, if anybody have the same problem you should add "${workspaceRoot}" to your path

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
How to access bootloader recovery mode (like the Micro) or equivalent on the Due?
I would eventually like to use a Due as a custom USB device PC-side (through programming port) while using it as a USB Host on the native port.
Adding the programming port endpoints (perhaps willingly removing the CDC endpoints) means I may break USB descriptors, or USB to PC communication generally speaking during development.
On the Micro that's not a problem because a double reset input lets me access the bootloader for 8s and reprogram the board even though I've removed CDC endpoints altogether. But on the Due, which I am not familiar with, I can see that a double reset input does not seem to have the same effect as my script starts right away. So I am quite scared to begin messing with the USB communications if I might just break my Due permanently (or rather, until I can recover it directly accessing the MCU).
Hence the question: is there some equivalent to the bootloader recovery of the Micro (& other older boards) on the Due ?

There is an "Erase" button on the Due to wipe your sketch and access the bootloader.

I didn't know that, thanks @Majenko. This solves my problem. Feel free to post this as an answer if you want it accepted. I'll edit the question to add "recovery" [mode].

I'm not sure if you're asking the right question though. It sounds like you're going to want to reprogram the USB interface chip, in which case the main MCU has no role in this...

Ah yes I'm very new to the Due so that didn't occur to me, but the programming port uses an external Serial to USB adapter, right ? So it's not the MCU's problem and I'm in for a ride if I try to mess with it. Whereas the native USB port is directly handled by the MCU, correct ?

That is correct. Making the programming port anything other than UART will be the same as if you're doing it to the UNO.


text:
Uno r3 - Can't get USB Keyboards to work with an USB Host Shield
I'm a day 1 beginner to Arduino, and I am trying to obtain input from a USB keyboard. I've connected the USB keyboard to an Arduino USB host shield attached to an Arduino Uno r3, and I am using the example HID sketch (USBHIDBootKeyboard.ino) provided with the USB Host Shield libraries : https://github.com/felis/USB_Host_Shield_2.0/blob/master/examples/HID/USBHIDBootKbd/USBHIDBootKbd.ino
I am powering the Arduino Uno r3 + USB Host Shield via USB. Upon init, only Start is written to the Serial Monitor. Tests show that SetReportParser exits with 0. Yet the keyboards are silent. I've tried three keyboards, all of which work properly when connected to the computer.
When using USBHidBootMouse.ino with a mouse, movements & buttons are perceived and print messages as intended.
https://www.circuitsathome.com/mcu/hid-support-for-usb-host-shield-library-2-0-released/ states that

Also, it is recommended to use external power supply while working with HID devices – I’ve seen many devices which would refuse to function when Arduino receives power from its USB port only.

EDIT : I tried to test if the power was the issue, so I used a 5V generator with intensity measurement. The results are : the Arduino Uno r3 uses 60mA, the keyboard uses 60 mA, connecting to the serial port uses 40 mA (much to my surprise).
This means the keyboard's power requirements shouldn't be the problem.
Then what would the problem be ? I'm helpless here. If the library linked on the official Arduino site doesn't work, then it should mean i'm using it wrong.

You should determine if this works when providing power.  If not, then it's more likely a software problem - keyboards and mice as similar, but different, and your keyboard code may not be correct.

You should probably also measure the voltage supplied to the USB peripheral, either at F2 on the board (hopefully a polyfuse not a one-time fuse), especially when loaded by a keyboard.  Or you could use one of those inline USB power meters assuming it is one which supports proper data passthrough.

@ChrisStratton It doesn't work when providing power. I've used a generator that supplied a 5V voltage while measuring the intensity : the arduino Uno itself uses 60mA, connecting it to the computer through serial uses 40mA (for a reason I don't understand), and connecting the keyboard uses 60mA. So it means the keyboard uses significantly less than 500mA, which means it's not the problem. So it - should - be a software problem ? But I'm only launching the library example sketch, so it not working is quite surprising. (EDITING OP IN PROGRESS)

see last paragraph of this page https://github.com/felis/USB_Host_Shield_2.0
it says this:

FAQ
When I plug my device into the USB connector nothing happens?
Try to connect a external power supply to the Arduino - this solves
  the problem in most cases.
You can also use a powered hub between the device and the USB Host
  Shield.
You should then include the USB hub library: #include <usbhub.h>
and create the instance like so: USBHub Hub1(&Usb);.

your keyboard may be multiple HID devices with a USB hub to connect them

A possibility, though less likely to be coincidentally true for the three keyboards reportedly tried, unless they are all the same and obviously all combo devices.

Thanks, I had missed this. As stated in my other answer, uncommenting the provided commented line "USBHub Hub(&Usb);" made it work for one keyboard, and I hastily thought it would work with others but didn't test it. The keyboard I tried is indeed a keyboard that accepts 2 other USB connections on its shell. The other 2 keyboards are simple keyboards, and the 3 are significantly different. I'm going to test these 2 with a hub instanciated and see if it makes them work.

I looked for the difference between USBHIDBootMouse & USBHIDBootKbd, and noticed line 100,

USBHub     Hub(&Usb);

was commented in the BootKbd side. Uncommenting it got the code to work.
I'm quite unsure how what interpretation to have from this. There should be a reason this line is commented in the library github.
Or maybe it is simply an error. In any case, uncommenting it got the code to work here.


text:
This logic level converter does not want to work
I got this logic level converter to be able to use my lcd but I can't figure out how to get it to work, the problem is that the current is not passing through. This is the model: TXS0108E

Any help is appreciated.
[EDIT]
A few Combinations that I have tried:

And I tried to swap the voltages, same wiring as in the pictures but 3.3v instead of 5v and vice versa.

Could you tell what you tried? Did you pull the OE pin HIGH?

@Gerben okay, i will add a few photos with what i have tried

@Gerben I made the edit

Assuming your lines saying "3.3V" are connecting to a 3.3V power supply, your first picture is correct. VA => 3.3V, OE => 3.3V, VB => 5V and GND => GND.

@Majenko the 3.3V are connected to the lcd, the 5v is connected to the 5v Pin on the arduino.

Where is the 3.3V coming from?

The GNDs for the 3.3V and 5V are connected? I.e. not from isolated sources. If missing the connections you made for testing? For example, connect GND to A1 and read voltage on B1. Connect Vcc-A to A1, and read voltage at B1

@Majenko the 3.3V is connected to the lcd, i want to lower the voltage from the arduino (5v) to 3.3v

@Gerben well, the lcd is connected to GND on the arduino and the GND on the board is connected to the arduino aswell

@Gerben This isn't the first time, and I doubt it'll be the last time, where I have seen someone assume that a logic translator like this magically provides a regulated voltage out from VCCA...

@Majenko sorry about the silly mistake, i'm still learing. I am working on a project for physics.

@xM0nSt3r It's ok - as I said, I've seen it before. You're not the first, so don't beat yourself up about it :)  Maybe I should design and sell a 5V -> 3.3V logic level shifter with built-in regulator. And maybe a 3.3V -> 5V shifter with built-in 3.3V->5V boost regulator for users of 3.3V Arduinos...

@Majenko that would help avoid these questions :)) start working then :P

The TSX0108 doesn't magically provide you with a regulated voltage. You have to provide the voltage, the TSX0108 merely switches it.
As you can see from the datasheet, the basic wiring is:

In the circuit above the 1.8V connection is your 3.3V connection, and the 3.3V is your 5V connection.
You must provide both the 3.3V and 5V power sources.

and how do i provide 3.3 v from an lcd?

By connecting it to a 3.3V power source - such as the 3.3V pin of the Arduino.

so i provide 3.3v and 5v from the arduino, and then that regulates the data pins voltage?

Crudely speaking, yes. It's just a set of switches. A signal coming in through an A pin switches the voltage provided at B to the matching B pin. A signal coming in through a B pin switches the voltage provided at A to the matching A pin.


text:
What's wrong with infinite loops inside loop()?
I wanted to run the following code as something similar to Tone or pwm. However for some reason that I am unable to seek it doesn't work.
#define WAIT 3200UL

void setup() {
  DDRB |= B00000001;  // set pin8 as output
}

void loop() {
  unsigned long t;
  while (1) {

    PORTB &= B11111110; // clear pin 8

    for (t = 0 ; t < WAIT; t++);

    PORTB |= B00000001; // set pin 8

    for (t = 0; t < WAIT; t++);

    //            PORTB &= B11111110;
    //            delayMicroseconds(WAIT);
    //            PORTB |= B00000001;
    //            delayMicroseconds(WAIT);

  }
}

the code is pretty simple, just toggling a pin. If I use the commented section, it works fine but as is, it doesn't work.
I removed the "while(1)" statement since it was unnecessary for now, it started to work improperly, (changing the WAIT didn't have any effect and I'm not sure I'm getting a full swing).
Pin 8 is connected to an LED + R to ground and a piezzo in parallel to them. the LED seems to be steady on yet the buzzer makes a low noise. I measured a   voltage of 3.8v DC and arround 9v AC on the pin, other pins I ran the code for were similar.
As another attempt I put a Serial.print in the beginning of the while(1) but it printed out only once.
Also looked at the assembly code generated for a clue to find out what does delayMicroseconds() do but couldn't figure out what's wrong.
Appreciate your help.

Answering your title - there's nothing wrong with an infinite loop within loop, but it's not necessary as loop itself is an infinite loop. Move unsigned long t; into setup and you will have an infinite loop without needing to explicitly code the while(1).

First, I will give you some unsolicited advise about your coding style.
Instead of writing:
PORTB &= B11111110;
...
PORTB |= B00000001;

you could write:
PORTB &= ~_BV(PB0);
...
PORTB |= _BV(PB0);

These are standard AVR idioms, and they make it clearer that you are
toggling the pin PB0.
Then, to answer your actual question, your delay loop does not work
because it got optimized-out by the compiler. This has already been said
in Michel Keijzers' answer, but let me elaborate.
All modern compilers are optimizing compilers. This means they can
change your code in whatever way they see fit, as long as the visible
effects remain the same. The effects considered visible are usually
I/O and access to variables declared volatile. Quite importantly, the
slowness of the program is not considered a visible effect for the
purpose of optimization. And if you think about it, it makes good sense:
if the slowness of the program were to be preserved, then any form of
optimization would be impossible. Thus, a loop that has no effect other
than slowing your program down can legitimately be optimized-out.
The solution to your problem is quite simple: if you want a delay, then
call delayMicroseconds(). Or maybe even delay() if you are OK with
its low resolution. On the other hand, if you need sub-microsecond
resolution, you can call _delay_us(), from the avr-libc. This function
(or rather, macro) provides single-cycle resolution. If you write
#include <util/delay.h>

...
_delay_us(1.375);

you get exactly what you ask for, i.e. a delay of 22 CPU cycles
(on an Arduino Uno clocked at 16 MHz). The issues with this
function are that it is AVR-specific, and its argument must be a
compile-time constant.
It has been suggested to you to write your delay loop using a volatile
loop counter. I strongly advise you against doing that, for three
reasons:

Doing so will force the counter to be allocated to RAM, thus
consuming a scarce and valuable resource for no good reason.
Incrementing a RAM-based 32-bit counter takes 20 CPU cycles. Add
to this the time required to test the end-of-loop condition and you
will realize that your delay resolution is way worse than that of
delayMicroseconds().
Your actual delay will depend on the clock frequency, and probably
also on the compiler's version, making your code pretty fragile.

Upvoted for the (much extra) explanation

Re, "effects considered visible are usually I/O and..."  There is no I/O in the C++ programming language.  The effects that are considered visible are calls to functions with external linkage, and access to volatile functions.  When a C++ program does something like std::cout<<"hello world!\n";, that's a call to an external library function.

static loop counter should work just as good in this particular case, saving some of the load/store instructions.

@jameslarge: Recent versions of the Arduino IDE pass the -flto option to the compiler, which triggers full-program link-time optimization. In this case, external linkage is irrelevant, and calls to external functions can be optimized out (yes, I tried).

@wondra: I tried with a static counter, both a global static and a local static. In both cases the loop got optimized-out, although the counter did get written with its end-of-loop value.

@EdgarBonet work for me using VisualStudio, seems that such construct mgiht be even more dangerous than initially expected. Another reason to use the delay from avr lib.

Oops!  I meant, ...access to volatile variables.

First
t = WAIT;
for (t = 0; t < WAIT; t++);

The first statement is not useful, since t will be assigned to 0 in the for loop.
However, since t is not used, probably it is optimized and removed by the compiler, meaning it will not perform a delay.
You should make t volatile. This prevents the compiler from optimizing it (out).
The only difference with or without the infinite loop is that variable t does not need to be allocated for (and keeps its value from the previous loop), but since the value is overwritten it does not make a difference.

Even t is marked volatile, the loop will execute that quickly you won't even see it flickering.

increasing the WAIT value might help ... not sure how many clock cycle are used. I would say 16 MHz / number of clock cycle for one iteration handling.

And a useful device to analyze this is a logic analyzer, you can buy it for 5 euro from China and is easier to use for low signal checking than a (cheap) oscilloscope.

Correct me if I am wrong, but t is used(read) in the t < WAIT expression and both written&read in the t++ expression. The fact that the statement of the for cycle is empty might make it target to compiler optimization for another reason, but it does not appear to me that t is unused.

it is not used afterwards and has no side effects, so the compiler can optimize it away.

Incrementing, comparing and jump is just a single digit of instructions. At max (65535) this is around 600000 tics, so 600000/16000000 = 37ms. So it SHOULD be a noticable flickering.

@Kwasmich why is 65535 the same as 600000  tics and not 65535 tics? Than it would be 3,7 ms and because in the example 32000 is used it would be appr. 2 ms or less which is probably unnoticable.

65535 loop iterations times single digit count of ticks (10 or less) is roughly 600000 (rounded for convinience), yes, 3200 is a pretty low delay.

I commented out the t=wait which was silly and  was left from a while(t--) ; structure but it's still the same, also I already had tried many different values to fall in a sensible range but still doesn't work. I guess the problem is somewhere else.

Check the time before/after a loop and see if it is optimized out (you can even put an extra for loop to check longer times).

@MichelKeijzers OK thanks! defining t as volatile solved the problem. but I'm still in doubt like the comment by @wondra  so I wrote it as for(t = 0; t < WAIT;) t++; but still the compiler ignore it unless defined as volatile. what exactly is using afterwards as @kwasmich also mentioned?

Probably what he meant is (and I put in my answer), is that when using volatile, you prevent the compiler to ignore the for statement. That is why it works with volatile and not works without volatile.


text:
Having really weird experience with string concat
Having really bad day with concat. I'm not quite sure where i did wrong..
Have a look at my function below.
void sim900aSendHttp(String bid, String lati, String longi) {
  Serial.println("BUSID:"+bid+",LAT:"+lati+"LONG:"+longi);
  String httpget = "http://uumresearch.com/bustracking/update_location.php?busid="+bid+"&latitude="+lati+"&longitude="+longi+"";
  //String httpget = "http://uumresearch.com/bustracking/update_location.php?busid=KDF8860&latitude=6.533415&longitude=106.33345";
  Serial.println(httpget);
  serialSIM800.println("AT+HTTPPARA=\"URL\",\"" + httpget + "\"");
  delay(3000);
  serialSIM800.println("AT+HTTPACTION=0");
  delay(8000);
}

The problem is with:
String httpget = "http://uumresearch.com/bustracking/update_location.php?busid="+bid+"&latitude="+lati+"&longitude="+longi+"";

where serial monitor only  shows
http://uumresearch.com/bustracking/update_location.php?busid=KDF8860

missing "lat" and "longi" variables in the string concat.
Both variable confirmed available to the function as printed by
Serial.println("BUSID:"+bid+",LAT:"+lati+"LONG:"+longi);

Which arduino board do you use?

+ on const char * increments the pointer. only String has + overloaded as concatenation of the right operand (not left). so "abc" + str + "efg" will not work even if str is String. What will work is String("abc") + str + "efg", but small Strings will fragment the heap memory of the MCU very fast and the sketch will crash.
Print the parts directly to serialSIM800 or use snprintf to build the strings or try CStringBuilder from my StreamLib


text:
DS18B20 flaky with LOLIN32 ESP32 board, rock-solid with Uno
I'm trying to read 4 DS18B20 sensor probes (https://amazon.com/gp/product/B00Q9YBIJI and https://amazon.com/gp/product/B008HODWBU) with a "Wemos" LOLIN32 ESP-32 board (https://amazon.com/gp/product/B072HBW53G).
Wiring:

The probes' Vcc wires are connected to the ESP32 board's "3.3" pin
the probes' ground wires are connected to one of the ESP32 board's "Gnd" pins
the probes' data wires are connected together at the end of their furnished meter-long cable, and the wire carrying the combined data is connected to GPIO 16 on the ESP32 board.
Additionally, there's a 4.7k resistor between GPIO16 and the 3.3v pin on the Lolin32 board to pull the 1-wire bus high.

I'm using the stock Arduino  and  libraries.
Sometimes, the sensors work. Often, they don't.
Possibly noteworthy is the fact that I purchased 1 probe a few years ago, and a 3-pack of probes this week. Probes from the 3-pack ONLY work if the probe I purchased earlier is ALSO connected. Put another way...
Original probe connected: sometimes works, sometimes doesn't.
1-3 of new probes connected: never works.
1-3 of new probes connected along with original probe: sometimes works, sometimes doesn't.
Wiring should theoretically be a total non-issue... I'm using only the original ~meter-long wires, with short (~3-4") AWG20 solid hookup wire soldered to the end and connected through a breadboard.
If I unplug the wires connected to the ESP32 board's GPIO16, 3.3, and Gnd pins and connect them instead to an old Arduino Uno's D2, 5v, and Gnd pins (and change the port in the code), all tested permutations of the sensors work perfectly and reliably.
Any ideas for troubleshooting this?
At the moment, these are my top theories:

GPIO16 is unsuitable for some unknown reason.
There's at least one software bug somewhere between the ESP32's low-level firmware, the firmware that enables an ESP32 to act like it's an Arduino, the two Arduino libraries themselves, or some combination of them all. Knowing that something like this is almost certainly the problem would at least spare me from going in circles for the next few days trying to solve a problem that can't be solved.
The 3 new sensors really don't like 3.3v, but the older one semi-tolerates 3.3v (theory fails to explain why adding a fourth sensor -- the original one -- would occasionally enable the 3 new ones to work)
The ESP32 board can't supply enough current from the 3.3v pin to properly power the sensors (flaws in theory: if it were purely lack of current capacity, adding the fourth sensor on top of the first 3 should make matters worse, not better. And in any case, the DS18B20 sensors don't use much power, and almost by definition MUST be able to work with unstable & intermittent power for parasitic powering to be capable of working. Just to emphasize, I am NOT using parasitic power, though).

I considered trying to feed the sensors 5v, but I'm not entirely sure how to deal with the level translation between their data bus and the ESP32 board.

I know Espressif has officially stated that the ESP8266 has 5v-tolerant i/o
I could swear I also read somewhere that the ESP32 is unambiguously NOT 5v-tolerant.
I have a hunch that level-shifting Dallas 1-wire is more complicated than it seems, and that there's probably at least one "gotcha" lurking that will cause problems if I try blindly using something like a TXB0104 or MAX3378 between the sensors' data wire and the ESP32 board.

Here's the relevant code (when it works, it works for the original sensor or the original sensor + one or more of the new sensors... when it doesn't work, it fails to detect any sensors & just outputs "Temp:   " to Serial when running in loop().
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 16
#define TEMPERATURE_PRECISION 12

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature dallasTempSensor(&oneWire);
int totalOneWireDevices = 0;
DeviceAddress tempDeviceAddress;

void setup() {
    Serial.begin(115200);

    dallasTempSensor.begin();
    totalOneWireDevices = dallasTempSensor.getDeviceCount();
    Serial.print("Locating devices...");
    Serial.print(totalOneWireDevices, DEC);
    Serial.println(" devices.");

    Serial.print("Parasite power is: ");
    if (dallasTempSensor.isParasitePowerMode())
        Serial.println("ON");
    else
        Serial.println("off");

    for (int x=0; x<totalOneWireDevices; x++) {
        if (dallasTempSensor.getAddress(tempDeviceAddress, x)) {
            Serial.print("Found device ");
            Serial.print(x, DEC);
            Serial.print(" with address: ");
            printAddress(tempDeviceAddress);
            Serial.println();
            Serial.print("Setting resolution to ");
            Serial.println(TEMPERATURE_PRECISION, DEC);
            Serial.print("Resolution actually set to: ");
            Serial.print(dallasTempSensor.getResolution(tempDeviceAddress), DEC);
            Serial.println();
        }
        else {
            Serial.print("Found ghost device at ");
            Serial.print(x, DEC);
            Serial.print(" but could not detect address. Check power and cabling.");
        }
    }
}

// function to print the temperature for a device

void printTemperature(DeviceAddress deviceAddress)

{
  float tempC = dallasTempSensor.getTempC(deviceAddress);
  //Serial.print("Temp C: ");
  //Serial.println(tempC);
  //Serial.print("Temp F: ");
  //Serial.print("    ");
  Serial.print(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

void loop() {
  // put your main code here, to run repeatedly
    //Serial.print("Requesting temperatures...");
    dallasTempSensor.requestTemperatures();
    //Serial.println("DONE");
    Serial.print("Temp:   ");
    for (int x=0; x < totalOneWireDevices; x++) {
        if (dallasTempSensor.getAddress(tempDeviceAddress, x)) {
            //Serial.print("Temperature for device: ");
            //Serial.println(x, DEC);

            printAddress(tempDeviceAddress);
            Serial.print(" = ");
            printTemperature(tempDeviceAddress);
            Serial.print("    ");
        }
    }
    Serial.println("");
    delay(5000);
}

void printAddress(DeviceAddress deviceAddress) {
    for (uint8_t x=6; x < 8; x++) {
        if (deviceAddress[x] < 16)
            Serial.print("0");
        Serial.print(deviceAddress[x], HEX);
    }
}

trying to read 4 DS18B20 sensor probes .... what about only one?

The original one sometimes works if it's the only one connected. The new ones never work if they're the only one(s) connected. The new ones sometimes work if they're connected along with the original one.

stop trying to run all four until you get one working rock solid ...... you either have a wiring problem or software problem or power supply problem or a combination of the three ..... please post your code, if you can

Code added. As noted, the only factor that seems to influence whether it works "sometime" or "not at all" is the presence of the original sensor... present, alone or with the others, the sketch sometimes works. Without the older sensor present, it never works.


text:
Suggested pullup resistor values for 1-wire network
I'm attempting to connect 6 DS18B20 temperature sensors to an Arduino GPIO pin in a topology that looks something like this:

Conceptually, it's a star network with two star subnets.
The GPIO pin on the Arduino is connected to point "E" through a 4-inch wire, a JST connector, and another 4-inch wire.
The 3 wires (shown in green) connecting sensors "A", "B", and "C" to point "D" are approximately 3 feet long (and are, in fact, the original ~1-meter wires that came pre-attached to the sensors when I bought them). Segment ED is ~4 feet long.
The 3 wires (shown in blue) connecting sensors "G", "H", and "I" to point "F" are approximately 20-30 feet long (including the original 3-foot wires attached to the sensors when I bought them). Segment EF is ~8 feet long.
No parasitic power is involved. Every DS18b20 has 3 wires... +5v (probably closer to 4.5v by the time it gets to G/H/I), ground, and 1-wire data.
So... where would YOU recommend putting resistors (feel free to describe points besides the ones I labeled with letters), and what values would you use?
And... would it actually be any better to take advantage of the fourth (presently unused) wire in the cables I have connecting G, H, and I to F as a 'return wire' to turn it into a much longer daisy chain (E to F, F to G, G back to F, F to H, H back to F, F to I), or something even more radical (say, ED, DA, AD, DB, BD, DC, CD, DE, then continuing the daisy chain with EF as described previously)?
For what it's worth, I presently have a single 4.7k pullup resistor sitting at point "E", and it seems to work... but after reading Maxim's AppNote about "Building reliable long 1-wire networks" (Appnote 148), I'm feeling like it shouldn't work, and that I really ought to do something more sophisticated for the sake of long-term reliability.

where would YOU recommend putting resistors?  ... that question seeks an opinion, which is off topic here ... perhaps ask what is the optimal location for a resistor?

Can you add link to that application note you mentioned? I would place one pullup at the master but I'm not aware of what Maxim suggest...

I think 4.5v is sufficiency unless you experiencing of getting reading of 85000. I once use 3.3v and started get some error reading 85000 if the supply line is noisy.

Added link to AN148

I have a linear network with three thermos at roughly 5', 20', and 40-50' from the micro (a 5v '328p), as well as being parasitically powered. The physical bus is a twisted pair from a Cat-5 cable. The pullup is 4.7KOhm on the processor board.
I've tested this network using a 3.3v '328p and it wasn't as reliable, but reducing the pullup to 2.2K (IIRC) fixed it.
I find Maxim's App Note 148, "Guidelines for Reliable 1-Wire Networks" to be very helpful and is my go-to for 1-wire network questions.


text:
CLion + Arduino -- Cannot find any CMake profile
I'm trying to get CLion 2019.2 working with Vladimir Schneider's Arduino Support plugin (v1.4.4, from the Jetbrains Plugin repository)
I installed MinGW from https://sourceforge.net/projects/mingw/ into c:\mingw, then went to Settings -> Build/Execution/Deployment -> Toolchains, added a new MinGW toolchain from c:mingw, and allowed it to autodetect make, gcc, and g++.
I got an error that GDB was too old,  selected "use bundled GDB", and the error went away.
I then created a new Arduino/Genuino Uno project, and attempted to build it.
At first, I was getting CMake Error at CMakeLists.txt:5 (set), due to line 5 being "set(${<@PROJECT_NAME@>}_BOARD uno)".
I found a post in the Arduino plugin's bug tracker said it's a bug in the plugin, and the work-around is to hand-edit CMakeLists.txt to replace every instance of "${<@PROJECT_NAME@>}" with "{PROJECT_NAME}" (apparently, there's a bug somewhere that causes it to wrap some environment variables with <@ and @>).
Now, I'm getting a different error whenever I try to build: "Cannot find any CMake profile"
I think I remember seeing a bug report thread for CLion itself speculating about the existence of a bug in CLion where the preferences UI implies that a configuration change has been made, but CLion doesn't actually update the file used by CMake to reflect the change. From what I recall, someone in the thread asked what specific file needed to be changed, and what specific changes were necessary... then the thread died without any subsequent posts for the past ~6 months.
Any ideas about what to try next?
Other relevant links for background info & context:
CLion's Arduino plugin by Vladimir Schneider: https://plugins.jetbrains.com/plugin/11301-arduino-support
Vladimir's project is a fork of an earlier plugin that was apparently broken by the release of CLion-2018.1. I'm under the impression that it still works for CLion 2019 under Linux, but was either broken by 2018.2 or 2019.1 for Windows, or never quite worked properly under Windows at all.
I've gotten the impression that, at least as of 2017-2018 (which is when a large number of postings about CMake-under-MinGW/Windows, CLion, and Arduino were made), CMake under Win32 via MinGW was still kind of buggy and brittle. The number of postings about them in 2019 is a lot smaller than 2017 and 2018, but I'm not sure whether that's because the problems people were talking about 2 years ago were solved, or because the people talking about them 2 years ago just got frustrated, decided it was a bit too bleeding-edge for them, and (at least temporarily) threw in the towel to wait for them to mature a bit.
Update: I just found another post theorizing that some of these problems might be due to limits imposed by Windows (by default) on the number of characters allowed in filename paths. I know Windows 10 allows you to increase the limit, but I know there are still a bunch of issues associated with doing that (Explorer can't touch anything with a path > 260 chars, cmd.exe -- and possibly Powershell -- requires using \\?\ notation, and Very Bad Things™ will happen if you physically attach a hard drive with files whose pathnames exceed the limit to a different computer running Windows that's still enforcing the old limit).
A tutorial for it that unfortunately seems to have gotten broken slightly by a subsequent release of CLion or one of its Arduino dependencies: https://vxlabs.com/2018/03/24/developing-arduino-sketches-with-jetbrains-clion-a-minimal-example/
(note to mods: I tried to tag this with "CLion" and "CMake", but the tags don't already exist, and my reputation isn't high enough yet to create new ones)

the reason that those tags do not exist is because they have nothing to do with an Arduino

Not quite. In theory, CLion can be used for C++ Arduino development (though, it appears, getting it to work with Windows instead of Linux is a major fragile ordeal at the moment), and CLion's "Arduino" plugin is CMake-based. It kind of feels as if CLion appeared on the scene right around the time CMake became relevant, and everyone writing Arduino plugins for it decided CMake was "the future"... and unfortunately, CMake STILL kind of appears to be "the future" (and not quite "the present"). See https://github.com/francoiscampbell/arduino-cmake


text:
Where do class files go in Sloeber Eclipse project?
I'm attempting to create a new Arduino project using Sloeber (Eclipse). Assume it's a newly-created project whose main entry file is ".\ArduinoMainClass.ino"
Now... assume I want to create a half dozen new classes:

ExecutionState-- a C++ class that's intended to be functionally equivalent to a Java Interface. If you're wondering, I'm attempting to implement the 'State' pattern.
GoodState, BadState, UglyState, WeirdState-- C++ classes that all extend ExecutionState. If they were Java, they'd technically be implementing an interface... but since this is C++ and I'm still taking baby steps, for now ExecutionState is just a class with one method that does nothing, and all of THESE classes override it to do the actual work.
StateContainer-- a C++ class whose only purpose in life is to hold single instances of GoodState, BadState, UglyState, and WeirdState. If this were Java, they'd be Singletons... GoodState (and the others) would have something like:

    private static ExecutionState instance = new GoodState();
    // ...
    public static ExecutionState getInstance() { return instance; }

... but it's obviously not Java,  and I'm nowhere close to knowing enough about C++ to properly implement static singletons yet, so for now, I'm just going to create an instance of StateContainer to create and hold those single instances.
So... I now have Sloeber/Eclipse loaded, and I've created my project. If this were Java, I'd create a subdirectory like .\src\java\com\packagename\executionstate and stick the .cpp and .hpp files for ExecutionState, GoodState, BadState, UglyState, WeirdState, and StateContainer in it, and add "include com.packagename.executionstate.*" to it.

I know C++ namespaces have no direct connection to directory names
I've gotten the impression that "Arduino"-ish C++ auto-generates the #include files for things it regards as libraries. I have a hunch that I probably want to put all of the classes I mentioned above in a directory somewhere and present them to the IDE as an Arduino "library" so they'll all get implicitly included in one go within the .ino file.
I'm completely confused about what I need to #include in the classes I mentioned above so they can mutually find each other... and whether those #includes rightfully belong in the .hpp or .cpp files.

So... getting back to the big picture. If my project is in c:\users\moi\Documents\Slober-workspace\FirstSloeberArduinoApp...

Where do the .cpp and .hpp files for ExecutionState, GoodState, BadState, UglyState, WeirdState, and StateContainer go? (Assume I'd be inclined to put them all in a directory named "executionstates" somewhere in the project's directory hierarchy, but I'm not sure where that exact directory should go).
What #includes do I need to put in ExecutionState, Good/Bad/Ugly/WeirdState, and StateContainer... and do they go in the .hpp file, or the .cpp file for their respective class?
What do I have to do so the .ino file can find StateContainer?

In case you're totally confused at this point, my actual .ino file will look something like this:
void setup() {
    // executionStates is a global variable declared higher up
    executionStates = new StateContainer();
    executionState = executionStates.getGoodState();
    // StateContainer's constructor itself creates instances of the various subclasses of ExecutionState,
   // and passes references to itself to their constructors so they can
   // get the references to the others states as they need to return them.
}

void loop() {
    executionState = executionState->doSomething();
    /* executionState holds a pointer to an instance of an ExecutionState subclass.
       Each time doSomething() executes, it returns a pointer to its new state
     */
}

... and in reality, there will be dozens of subclasses of ExecutionState, each representing a unique execution state.

''Arduino'-ish C++ auto-generates the #include files for things it regards as libraries." The Arduino IDE, being a learning tool for new programmers, does do this, but it is unique to that environment. Having graduate to a professional level tool (Eclipse/Sloeber) which will save you a tremendous amount of tedium - but not fixing your code for you - be prepared to write standards-compliant C++, even if using the Arduino IDE. You will, in the long run, make fewer opportunities for error, come to understand the language better, and your code will be portable to standards-compliant environments.

With Sloeber Eclipse plugin the ino files go to root of the project and the cpp, c and h files can be in root or in subfolders. example:

Folders created by Sloeber: core subfolder is a virtual folder with links to Arduino core files and variant files of the selected board. libraries folder is a virtual folder with links to libraries selected for the project. Release folder contains the generated make file, the .o files and the resulting elf, hex, bin files. (And sloeber.ino.cpp is a file generated by Sloeber)
Project folders: data folder in example picture is a convention for a folder with esp8266 SPIFFS files. utility is a subfolder with additional source files of the project.

I put my class files, [class].cpp and [class].h, in the same folder as my project.ino file, at least during development. Then, if they're sufficiently general, I'll move them to [workspace]/libraries/[class]/ for future use.
But even if they're only for this project (so they might as well stay in the project's source code folder), it's good organization to keep them in their own files, since by nature, classes only expose their interfaces, not their "guts".


text:
Enable full float-capable snprintf() library with PlatformIO
I want to use snprintf() to format floats to a string.
I know the "normal" version of Arduino's avrlibc had all the float-formatting code removed to make it smaller.
I also know that at some point in the fairly recent past, it became possible to force gcc to use an alternate (forked?) larger Arduino avrlibc that had all the float-formatting functionality that was originally removed put back in.
However... I'm still trying to find an actual explanation of how to do that for an Arduino project using PlatformIO.
I found a clue someplace where someone said, "change linker rules in platform.txt file to enable floating point xxprintf()" (which hopefully enables floating point support in other float-to-string functions as well).
Problem #1: platform.txt appears to be global rather than local to this one project. There's no file named "platform.txt" anywhere in the project's directory.
Problem #2: I do have several dozen files on my computer named platform.txt... I don't know which one is the one that actually matters to PlatformIO, and I don't know enough about PlatformIO's internals to know how to figure out which platform.txt is the one that matters.
Problem #3: Even if I manage to figure out which platform.txt is the one I need to modify, I still don't know what exact modifications actually need to be made.

Update: I stumbled over a thread in Arduino's Issue discussion ("Sprintf for floats on Arduino Mega 293") that said to append the text quoted further down to boards.txt. The relevant line appears to be mega.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
So... I'm guessing that what I need to put somewhere in platform.txt (once I figure out which platform.txt is the one that matters) is -Wl,-u,vfprintf -lprintf_flt
##############################################################

menu.printf=AVR printf Version
menu.scanf=AVR scanf Version

yun.menu.printf.default=Default printf
yun.menu.printf.default.avr_printf_flags=
yun.menu.printf.full=Full printf
yun.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
yun.menu.printf.minimal=Minimal printf
yun.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

yun.menu.scanf.default=Default scanf
yun.menu.scanf.default.avr_scanf_flags=
yun.menu.scanf.full=Full scanf
yun.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
yun.menu.scanf.minimal=Minimal scanf
yun.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

yun.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

uno.menu.printf.default=Default printf
uno.menu.printf.default.avr_printf_flags=
uno.menu.printf.full=Full printf
uno.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
uno.menu.printf.minimal=Minimal printf
uno.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

uno.menu.scanf.default=Default scanf
uno.menu.scanf.default.avr_scanf_flags=
uno.menu.scanf.full=Full scanf
uno.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
uno.menu.scanf.minimal=Minimal scanf
uno.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

uno.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

diecimila.menu.printf.default=Default printf
diecimila.menu.printf.default.avr_printf_flags=
diecimila.menu.printf.full=Full printf
diecimila.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
diecimila.menu.printf.minimal=Minimal printf
diecimila.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

diecimila.menu.scanf.default=Default scanf
diecimila.menu.scanf.default.avr_scanf_flags=
diecimila.menu.scanf.full=Full scanf
diecimila.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
diecimila.menu.scanf.minimal=Minimal scanf
diecimila.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

diecimila.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

nano.menu.printf.default=Default printf
nano.menu.printf.default.avr_printf_flags=
nano.menu.printf.full=Full printf
nano.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
nano.menu.printf.minimal=Minimal printf
nano.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

nano.menu.scanf.default=Default scanf
nano.menu.scanf.default.avr_scanf_flags=
nano.menu.scanf.full=Full scanf
nano.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
nano.menu.scanf.minimal=Minimal scanf
nano.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

nano.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

mega.menu.printf.default=Default printf
mega.menu.printf.default.avr_printf_flags=
mega.menu.printf.full=Full printf
mega.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
mega.menu.printf.minimal=Minimal printf
mega.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

mega.menu.scanf.default=Default scanf
mega.menu.scanf.default.avr_scanf_flags=
mega.menu.scanf.full=Full scanf
mega.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
mega.menu.scanf.minimal=Minimal scanf
mega.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

mega.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

megaADK.menu.printf.default=Default printf
megaADK.menu.printf.default.avr_printf_flags=
megaADK.menu.printf.full=Full printf
megaADK.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
megaADK.menu.printf.minimal=Minimal printf
megaADK.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

megaADK.menu.scanf.default=Default scanf
megaADK.menu.scanf.default.avr_scanf_flags=
megaADK.menu.scanf.full=Full scanf
megaADK.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
megaADK.menu.scanf.minimal=Minimal scanf
megaADK.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

megaADK.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

leonardo.menu.printf.default=Default printf
leonardo.menu.printf.default.avr_printf_flags=
leonardo.menu.printf.full=Full printf
leonardo.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
leonardo.menu.printf.minimal=Minimal printf
leonardo.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

leonardo.menu.scanf.default=Default scanf
leonardo.menu.scanf.default.avr_scanf_flags=
leonardo.menu.scanf.full=Full scanf
leonardo.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
leonardo.menu.scanf.minimal=Minimal scanf
leonardo.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

leonardo.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

micro.menu.printf.default=Default printf
micro.menu.printf.default.avr_printf_flags=
micro.menu.printf.full=Full printf
micro.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
micro.menu.printf.minimal=Minimal printf
micro.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

micro.menu.scanf.default=Default scanf
micro.menu.scanf.default.avr_scanf_flags=
micro.menu.scanf.full=Full scanf
micro.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
micro.menu.scanf.minimal=Minimal scanf
micro.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

micro.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

esplora.menu.printf.default=Default printf
esplora.menu.printf.default.avr_printf_flags=
esplora.menu.printf.full=Full printf
esplora.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
esplora.menu.printf.minimal=Minimal printf
esplora.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

esplora.menu.scanf.default=Default scanf
esplora.menu.scanf.default.avr_scanf_flags=
esplora.menu.scanf.full=Full scanf
esplora.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
esplora.menu.scanf.minimal=Minimal scanf
esplora.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

esplora.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

mini.menu.printf.default=Default printf
mini.menu.printf.default.avr_printf_flags=
mini.menu.printf.full=Full printf
mini.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
mini.menu.printf.minimal=Minimal printf
mini.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

mini.menu.scanf.default=Default scanf
mini.menu.scanf.default.avr_scanf_flags=
mini.menu.scanf.full=Full scanf
mini.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
mini.menu.scanf.minimal=Minimal scanf
mini.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

mini.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

ethernet.menu.printf.default=Default printf
ethernet.menu.printf.default.avr_printf_flags=
ethernet.menu.printf.full=Full printf
ethernet.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
ethernet.menu.printf.minimal=Minimal printf
ethernet.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

ethernet.menu.scanf.default=Default scanf
ethernet.menu.scanf.default.avr_scanf_flags=
ethernet.menu.scanf.full=Full scanf
ethernet.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
ethernet.menu.scanf.minimal=Minimal scanf
ethernet.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

ethernet.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

fio.menu.printf.default=Default printf
fio.menu.printf.default.avr_printf_flags=
fio.menu.printf.full=Full printf
fio.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
fio.menu.printf.minimal=Minimal printf
fio.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

fio.menu.scanf.default=Default scanf
fio.menu.scanf.default.avr_scanf_flags=
fio.menu.scanf.full=Full scanf
fio.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
fio.menu.scanf.minimal=Minimal scanf
fio.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

fio.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

bt.menu.printf.default=Default printf
bt.menu.printf.default.avr_printf_flags=
bt.menu.printf.full=Full printf
bt.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
bt.menu.printf.minimal=Minimal printf
bt.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

bt.menu.scanf.default=Default scanf
bt.menu.scanf.default.avr_scanf_flags=
bt.menu.scanf.full=Full scanf
bt.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
bt.menu.scanf.minimal=Minimal scanf
bt.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

bt.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

LilyPadUSB.menu.printf.default=Default printf
LilyPadUSB.menu.printf.default.avr_printf_flags=
LilyPadUSB.menu.printf.full=Full printf
LilyPadUSB.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
LilyPadUSB.menu.printf.minimal=Minimal printf
LilyPadUSB.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

LilyPadUSB.menu.scanf.default=Default scanf
LilyPadUSB.menu.scanf.default.avr_scanf_flags=
LilyPadUSB.menu.scanf.full=Full scanf
LilyPadUSB.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
LilyPadUSB.menu.scanf.minimal=Minimal scanf
LilyPadUSB.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

LilyPadUSB.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

lilypad.menu.printf.default=Default printf
lilypad.menu.printf.default.avr_printf_flags=
lilypad.menu.printf.full=Full printf
lilypad.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
lilypad.menu.printf.minimal=Minimal printf
lilypad.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

lilypad.menu.scanf.default=Default scanf
lilypad.menu.scanf.default.avr_scanf_flags=
lilypad.menu.scanf.full=Full scanf
lilypad.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
lilypad.menu.scanf.minimal=Minimal scanf
lilypad.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

lilypad.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

pro.menu.printf.default=Default printf
pro.menu.printf.default.avr_printf_flags=
pro.menu.printf.full=Full printf
pro.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
pro.menu.printf.minimal=Minimal printf
pro.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

pro.menu.scanf.default=Default scanf
pro.menu.scanf.default.avr_scanf_flags=
pro.menu.scanf.full=Full scanf
pro.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
pro.menu.scanf.minimal=Minimal scanf
pro.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

pro.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

atmegang.menu.printf.default=Default printf
atmegang.menu.printf.default.avr_printf_flags=
atmegang.menu.printf.full=Full printf
atmegang.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
atmegang.menu.printf.minimal=Minimal printf
atmegang.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

atmegang.menu.scanf.default=Default scanf
atmegang.menu.scanf.default.avr_scanf_flags=
atmegang.menu.scanf.full=Full scanf
atmegang.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
atmegang.menu.scanf.minimal=Minimal scanf
atmegang.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

atmegang.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

robotControl.menu.printf.default=Default printf
robotControl.menu.printf.default.avr_printf_flags=
robotControl.menu.printf.full=Full printf
robotControl.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
robotControl.menu.printf.minimal=Minimal printf
robotControl.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

robotControl.menu.scanf.default=Default scanf
robotControl.menu.scanf.default.avr_scanf_flags=
robotControl.menu.scanf.full=Full scanf
robotControl.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
robotControl.menu.scanf.minimal=Minimal scanf
robotControl.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

robotControl.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

robotMotor.menu.printf.default=Default printf
robotMotor.menu.printf.default.avr_printf_flags=
robotMotor.menu.printf.full=Full printf
robotMotor.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
robotMotor.menu.printf.minimal=Minimal printf
robotMotor.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

robotMotor.menu.scanf.default=Default scanf
robotMotor.menu.scanf.default.avr_scanf_flags=
robotMotor.menu.scanf.full=Full scanf
robotMotor.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
robotMotor.menu.scanf.minimal=Minimal scanf
robotMotor.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

robotMotor.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

gemma.menu.printf.default=Default printf
gemma.menu.printf.default.avr_printf_flags=
gemma.menu.printf.full=Full printf
gemma.menu.printf.full.avr_printf_flags=-Wl,-u,vfprintf -lprintf_flt
gemma.menu.printf.minimal=Minimal printf
gemma.menu.printf.minimal.avr_printf_flags=-Wl,-u,vfprintf -lprintf_min

gemma.menu.scanf.default=Default scanf
gemma.menu.scanf.default.avr_scanf_flags=
gemma.menu.scanf.full=Full scanf
gemma.menu.scanf.full.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_flt
gemma.menu.scanf.minimal=Minimal scanf
gemma.menu.scanf.minimal.avr_scanf_flags=-Wl,-u,vfscanf -lscanf_min

gemma.compiler.c.elf.extra_flags={avr_printf_flags} {avr_scanf_flags}

##############################################################

Update 2:
I found what appears to be the solution & posted it as my own answer, but I'm going to hold off for a day or two to test it thoroughly and make sure it actually works.

For the record, both the “normal” and the “alternate” avr-libc are parts of the regular avr-libc. From the documentation of <stdio.h>: “In order to allow programmers a code size vs. functionality tradeoff, the function vfprintf() which is the heart of the printf family can be selected in different flavours using linker options.”

I finally found the answer at https://github.com/sstaub/LCDi2c
When using PlatformIO, add the following line to platformio.ini to enable full support for floats to printf():
build_flags = -Wl,-u,vfprintf -lprintf_flt -lm
Caution:
This solution increases the amount of required flash by at least 2k. If you're using a Mega2560, you probably have flash to burn and really don't care. If you're using an Uno, Leonardo, Nano, or some other smaller AVR-based variant... it might matter, and you might have to care.
Tip: if the Nano/Leonardo/Uno doesn't have enough flash or SRAM, but you don't have space for a full-blown Mega2560, consider the "Arduino Nano Every". It uses the ATMega4809, with 48k flash and 6k SRAM.