text:
Arduino send commands fast
I need cnc machine to run as smooth as possible.
It receives commands like this "M_XY 10.233 20.123".
If i send command by command there is a slight delay between commands and its noticeable.
I set serial timeout to 5 ms.
I tried to send n commands and store them on arduino, but arduino cant store much in ram. There is a huge delay while sending n commands.
I was thinking about converting letters (machine writes letters) to bezier and sending arc by arc or letter by letter in arcs. Can atmega328p interpolate bezier fast enough?
Would it be faster if i send numbers in bytes instead of strings?
That would be 4 bytes per float and merge with union on arduino.
Is there any better way of doing this i don't know of?
Edit:
This is how string commands are processed.
void addCommByte(const byte b){
  if(commID == MAX_COMM+1){
    commID = 0;
    Serial.println("TOO LONG COMMAND");
    Serial.flush();
    return;
  }

  if(b == '\n'){
    comm[commID] = '\n';
    commID = 0;

    processCommand();
  }
  else if(b == '\r')
  {
    commID = 0;
  }
  else
  {
    comm[commID++] = b;
  }
}

void loop() {
  Serial.flush();
  while(Serial.available() > 0) {
    addCommByte(Serial.read());
  }
}

Edit. Way better way.
C# side. Check for endianness in c#. Arduino is little endian.
        public void MOV_X(float mm)
            {
                SendCharAsByte("q"[0]);
                SendFloatAsBytes(mm);
            }
        public void SendFloatAsBytes(float f)
        {
            byte[] vOut = BitConverter.GetBytes(f);
            serialPort.Write(vOut, 0, 4);
        }

        public void SendShortAsBytes(short f)
        {
            byte[] vOut = BitConverter.GetBytes(f);
            serialPort.Write(vOut, 0, 2);
        }

        public void SendCharAsByte(char c)
        {
            byte[] aaa = new byte[1];
            aaa[0] = (byte)c;
            serialPort.Write(aaa, 0, 1);
        }

Arduino side.
void loop() {
  while(Serial.available() > 0) {
    processV2(Serial.read());
  }
}
// from processV2
if(byt == 'q'){   // mov x
    float mm = readFloat();
    if(X_DIR == 1) mm *= -1.0;

    stepperXY.moveXForMMSync(mm);
    Serial.println("p");
    return;
  }
// merge bytes
union u_tag {
   byte b[4];
   float fval;
} u;

float readFloat(){
  Serial.readBytes(u.b, 4);
  return u.fval;
}

There is no need to flush serial.

If you're receiving the serial data properly then there is never any need for a serial timeout. You shouldn't be relying on Serial.parseFloat() and such functions.

I'm using String c = Serial.readString(); in loop.

And therein lies your problem. You are reliant on a timeout. Instead you should be looking for the end-of-line character and reading the data up until you see that. And also don't use String as that will cause your system to crash randomly.

https://majenko.co.uk/blog/reading-serial-arduino

Please include a compilable minimal example code in your question. You can cut out all the CNC parts and just leave the Serial communication code. Please make sure, that the code is still compilable

I switched to char by char and its faster. Delay is still noticeable.

Why are you flushing Serial in loop? As I remember, firmware like GRBL also uses ASCII based communication to directly send the gcode to the CNC. So that can work. What are you doing to process the command? Are you measuring the delay between sending the command and the motor moving? How long is it now?

I did Boggyman's idea. There is still slight delay, but its acceptable. I'm using thread for command sending and receiving commands loop. That delay might be coming from c# thread.sleep loop. Somewhere i read that thread cant sleep less than 12 or so ms. Something windows os related.

If you have an existing CNC, you may have to abide by its comm protocol.  Otherwise, if the Arduino is part of a CNC you are building, and it is supposed to accept commands from a host computer, the first thing to do is make sure your baud rate is set higher than the default.  I have found 115200 to be a good choice for stability.  Next, you should avoid sending TTY-type text strings, and send binary values instead. You'd send an initial byte or word to specify the command type, followed by the data.  In my open-source DaqPort sketch for high-speed data acquisition https://www.daqarta.com/dw_rraa.htm I use the high nybble of the command to specify the general type, and the low nybble to specify more detail like channel number.  The sketch uses a big loop with if(Serial.available() > 0) to read the first byte, and a switch/case to determine what to do.  The the specific command reads the proper number of bytes and does whatever.  This is way faster than having to parse text and convert to binary.


text:
Reading from EEPROM and writing to addressable LED with limited connections
UPDATE
Clock speed code has been tweaked as per the suggestion from @timemage due to inability for Wire library to reduce to below 30304Hz. Unfortunately problems still persist:
Nothing printed out to serial and LED working only after disconnecting and reconnecting the circuit(stops updating after reseting arduino)..
UPDATE
Thanks for all replys. I have left the circuit the same and have used the following code where i have tried to reduce the i2c clock speed to 1khz but unfortunately having no luck.The EEPROM returns nothing and the pixel fails to work initially, only when i disconnect the circuit(this is simple because i am using a magnetic USB connector) it seems to work fine(until i restart the arduino).
If the consensus is that i may have more luck if I alter the library then i may look into it although it sounds a bit out of my depth...
#include <Wire.h>

#define disk1 0x50    //Address of eeprom chip
unsigned int address0 = 0; //address to store the data

#include <Adafruit_NeoPixel.h>

//pixels pin
#define sda_pin A4
#define scl_pin A5

Adafruit_NeoPixel strip(1, sda_pin, NEO_GRB + NEO_KHZ800);

void setup() {

  Serial.begin(9600);

  Wire.begin();

  ////UPDATED CODE TO REDUCE I2C CLOCK SPEED TO 1KHZ////
  TWSR |= 0x03; // chose divide-by-64 prescaler
  TWBR  = 0x80; // closest to 1 kHz from below at 16 MHz with /64 prescaler.

  Serial.println(readEEPROM(disk1, address0), DEC);
  Wire.end();
  pinMode(scl_pin, INPUT);

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(100); // Set BRIGHTNESS to about 1/5 (max = 255)

}

void loop() {
  rainbow(10);
}

void rainbow(int wait) {

  static unsigned long timer = 0;
  static long firstPixelHue = 0;

  if (millis() - timer > wait) {
    timer = millis();

    for (int i = 0; i < strip.numPixels(); i++) { // For each pixel in strip...

      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());

      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show(); // Update strip with new contents

    if (firstPixelHue < 5 * 65536) { //incrememnt
      firstPixelHue += 256;
    } else firstPixelHue = 0; //reset

  }
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
  byte rdata = 0xFF;

  const uint8_t i2c_base_address = 0x50;
  const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
  const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
  Wire.beginTransmission(i2c_address);
  Wire.write(eeaddress & 0xFF); // address LSB

  Wire.endTransmission();

  Wire.requestFrom(deviceaddress, 1);

  if (Wire.available()) rdata = Wire.read();

  return rdata;
}

ORIGINAL POST:
I have created a circuit which includes an AT24C16 EEPROM which I only need to read from and an addressable LED (WS2812 IC), which I will be talking to (Using an Arduino Nano).
My original intention was to attach the LED's DIN pin to either SCL or SDA. I thought that since I only needed to read the EEPROM once (and then control the LED), I would be able to share the connection. After creating the circuit, it proved an incorrect assumption.
I am limited to 4 (nets?) total due to the adapter I am using between the Arduino Nano and the rest of the circuit (repurposed magnetic 4 wire USB cable). Could anyone propose a setup which would allow me with only these 4 connections, to read from the EEPROM and write to the LED? As I mentioned, I only need a single read from the EEPROM to identify it and then I will only be writing to the pixel. Many thanks!
Attached is the schematic.

The problem may be that the input impedance of the WS2812 is low enough, as to pull the weak 35kOhm pull-up resistor below the voltage needed for the EEPROM to read as HIGH. I'd first give it another go with proper value pull-up resistors for I2C. Something as low as a 1kOhm. After that you could try adding a buffer circuit to the WS2812s input.

It seems like you have perfectly good answers already, but I am curious as to what you meant by "it proved an incorrect assumption."  Presumably, you did something that served as proof.  What exactly was that?

the circuit worked(could read the EEPROM) and then i added the LED and it stopped working(could no longer read EEPROM or control LED)

ps. thanks for all these replys, very interesting, ive not been able to test today but will get back to you as soon as i have)

Try the setClock fix suggestion in my "answer" and if that doesn't make one of the proper answers work for you.

I used your code with a 24LC02B, UNO, and 12 "NeoPixel" ring, which is the equivalent to what you have under this test.  On my setup, your code prints the first byte of EEPROM and then color cycles the first RGB LED.  So far as I can tell, this is the expected outcome.

Sth different: you know that the atmega328 has an internal eeprom, right? Do you have a reason to use an external eeprom? Just asking...

Do you actually have pullups on the bus lines? I see no reason why the eeprom should not be readable with the WS2812 connected, so that might be the root issue to solve

hi yes i am aware of that. i am using the eeprom as a means to identify swappable modules. i initially did have physical pullups but heard that the wire library uses internal pullups so i removed them and the circuit worked fine(for reading eeprom,before adding the pixel). i have just tried adding them again and the situation remains the same...

I can put my setup in answer if you want, but I doubt there's anything to be learned from it.  The UNO is pretty much electrically the same as Nano, at least in all the ways relevant to the test.  The 24LC02B I'm using has the same pin out, same I2C address, and same "commands" as your device.  It just has less memory.  I didn't bother putting pullups on the I2C bus because the internals were sufficient to make the code work to prove that it can be done.

Well i suppose theres no harm in trying. other than that the only thing i can think of is to buy that exact chip and try to replicate it. I only need the eeprom to use as a means to identify modules so any ic would do.

My working details, per-request
Setup
So, the setup is the same as you what you have in its essentials:

The code is your code with the near-1 kHz tweak.  That said, I believe I also tested it at the default rate and that worked as well.  In any case, the images that show the LED changing were taken while that 1 kHz adjustment was made.

The UNO and Nano are functionally identical for this.  They use different serial transceivers which has nothing to do with anything.   The Nano will typically have a lower "5V" than the UNO when USB powered owing to the Nano using a diode where the UNO has a FET.  Which is unlikely to matter either.  They're otherwise the same device so far as the setup goes.

The 24LC02B uses the same pinout and I2C address and command-sequences as your AT24C16.  It is a smaller memory, not that it makes a difference; we're reading from address 0.  I did not find I necessary to add external pull-up resistors and it worked, so it seemed unnecessary to add them to demonstrate that it can work since adding them should only improve it's chances for working correctly.

The LEDs are the Adafruit ADA1643 12 Neopixel Ring. We're both using the first LED of a string, doesn't really matter how long the are.   We're only lighting one "pixel" so I just powered it from USB.  Have no idea what you're doing there.  But for one LED lit, I doubt a difference there would matter much.

You'll see a resistor connecting SDA at the EEPROM to IN on the addressable LED(s).  I put that there in case by some chance the EEPROM could drive SDA low while the addressable LED code was driving the LED data line high. while.  I doubt that can happen, but it was a small thing to do.  For what it's worth, I did run it briefly without it in series, and it also worked fine that way as well.  I'm only telling you this so you have all the information and not because I think it matters; I don't.

Running
It prints out 72.  This is the first value in my EEPROM. The 'H' of "Hello world" basically.  And then it goes on to cycle the first addressable LED of the set through all of the colors.
Configuration Pictures

OK, thanks again for taking the time to do this, i am indebted to you! I tried your exact setup and....still didnt work! But....on a whim i decided to change the LED, and it worked! It turns out that i have 2 addressable LED strips, one is a 60 led / meter strip and the other 30 led / meter strip. the 60/m ones work and the 30/m ones dont! how flipping weird(and frustrating) is that!? so, this is now sloved, albeit in a rather convoluted fashion. Do you have any suggestions on how i should update this in the most helpful way? should i create another answer or is it a bit too rough?

Maybe this is all you're seeing.

This is just a hacky idea how you could solve this.
Decrease the I2C frequency below 10kHz or - as you only want to read the eeprom once at start - even down to 1kHz. This way the WS2812 will see a series of low pulses with a duration >50us which it should take as a reset signal. Practically, the WS2812 will ignore such a signal.
But there's a different problem: the EEPROM will write to the bus occasionally whenever it receives something that looks like its address. This in turn can

interfere with WS2812 communication.
damage the EEPROM's I2C interface if you control the WS2812 with push/pull signal (by setting gpios HIGH/LOW).

It would be safe to drive the WS2812s with an open drain signal (switching between LOW and INPUT), but that might require modifications to the WS2812 library.
In any case you should use the SDA line to control the WS2812 and there must be no signal on SCL while controlling the light (the EEPROM won't communicate if it receives no clock signal). The easiest might be to deactivate I2C entirely once you don't need it anymore and explicitly set the SCL pin to input mode. You then should be fine using SDA in normal push/pull mode and the library should work just as normal.

hi there, thanks very much for this,I have updated my question in response.

setClock(1000) Problem
This is sort of answer material, but it's meant to be supplementary to the other answers that more directly address your question and quite well, I think, though I'm unable to test right now.  So if you find this helpful, vote it up, but mark one of the others accepted if this tweak makes it work.
Specifically to address this content in your update:

I have tried to reduce the I2C clock speed to 1khz but unfortunately
having no luck.

And your line:
Wire.setClock(1000);

I was curious to know exactly how setClock maps its argument onto the values of  clock rate generating parameters in the hardware registers and whether or not 1 kHz might not be too slow for an AVR running at 16 MHz.  That is, perhaps the lower bound might be say 50 kHz, at which I'd've suggested a bit-banging I2C library in a comment to your question; however that's not the case.
In investigating this, I found that setClock fails spectacularly to do anything sensible in the AVR Arduino core library if given an argument of below 30304.  Requested rates below this figure wind up yielding rates much higher than this owing to how they're calculating the clock rate with the TWI/I2C/"Wire" prescaler (TWPS1 and TWPS0 in TWSR) and the bit-rate register (TWBR).
I dug in to see what causes setClock to behave poorly for low rates, and there's not a lot to it.  The I2C/Wire prescaler is set to divide-by-1 and left that way.  setClock calls twi_setFrequency, which calculates TWBR using this expression:
TWBR = ((F_CPU / frequency) - 16) / 2;

At 30304 Hz and above, this generates something within 1% of the desired frequency.  Along the x-axis is the requested rate.  The y-axis shows the effective rate.  Unsurprisingly, roughly linear.

But below 30304 Hz, things go sideways. Values of 30303 or less when fed into that expression try to calculate a TWBR of 256 or greater.  But, it's an 8-bit register, so it rolls over. To prevent that a different prescaler would need to be selected.  But, it isn't and the following craziness results:

What setClock(1000) is actually doing in your code is setting a rate of 125 kHz; I have verified this on a scope.
Suggestion
You can get an approximation of a 1 kHz clock rate by manually setting the hardware registers yourself, replacing your setClock line with the following:
TWSR |= 0x03; // chose divide-by-64 prescaler
TWBR  = 0x80; // closest to 1 kHz from below at 16 MHz with /64 prescaler.

This should give you a TWI/I2C rate of about 975.61 Hz.  In the datasheet for the ATMega328P you'll see this is selecting the divide-by-64 prescaler, and taking 128 ticks of that. You can find the equation in the datasheet, that if you fill these values and your UNO clock rate into, gives the expression 16e6 / (16 + 2 * 0x80 * 64), which gives you the 975.61 figure above.  I've verified that it is approximately that on a scope.
Give that a try.  See if when you do, whether or not one of the answers doesn't work for you.  I expect one will.

Thanks again for such a thorough investigation, its enormously appreciated. Unfortunately the problem still persists, I have updated my question in response.

The AT24C16 is an I2C bus device but the WS2812 is not.  If you can tolerate spurious outputs on the WS2812 LEDs, you can read the AT24C16 using I2C by addressing the device properly.  The WS2812 will "listen" and may display things as that traffic is flowing past it.
When you are finished with the AT24C16 you will probably need to disable the I2C controller (assuming you are using that) and then hold the SCL line HIGH and then communicate with the WS2812 using the SDA line only.  The AT24C16 will ignore this non-I2C traffic because the SCL line is static a this point.

my initial thinking was that there may be some 'spurious outputs' from the led while the EEPROM is being read but since it only takes a short time it would be ok. unfortunately the EEPROM fails to read when the pixel is connected as per the schematic.

This won't work with 24Cxx EEPROMS.
The I2C bus works this way:

Master writes out an address.
Slave takes over the SDA line and pulls it high or low to indicate an ACK or NAK.
Master writes out a command for reading from an address.
Again Slave takes over SDA and ACKs the command.
Master is continuing to pulse SCL while Slave puts out data to SDA.
After every byte (or word) Master has to take over SDA to confirm the data has been received.

So there is no way to tell the EEPROM to just vomit all its data to a bus without someone actively listening and ACK-ing. Which in turn changes the data on the bus.

It might work with 25Cxx EEPROMS.
You would need something different which has a much simpler communication scheme.
An 25Cxx which uses SPI for example, supports reading in a sequence, without constant ACK-ing. You will have to just initialize the read and keep clocking on SCK. No back and forth.
The data will be output to MISO in sequence.
But then still you will have to get the timings right. WS2812 are not very forgiving in that regard. That is why most people use libraries that have handcrafted Assembler code in them to get the timinigs right.
And I know what I am talking about as I wrote some myself (not suitable for anyone but me).
https://kwasi-ich.de/blog/2019/11/15/pwm_rider/

"Won't work with 24Cxx EEPROMS" - I think it does as I wrote in my answer

"the EEPROM to just vomit all its data to a bus without someone actively listening and ACK-ing" - no one will ACK here, WS2812 are no I2C devices and other I2C devices won't ACK if they don't get addressed

Yes, I misunderstood the intention. I thought the data for the WS2812 should be comming from the EEPROM directly via SDA. MCU telling EEPROM to output its data to the bus where WS2812 would listen.

source: Stack Exchange

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

sort: votes


text:
Trying to improve speed of downloading files from server and writing to SPIFFS
update I have updated the code(second code segment) so that the null character is inserted into the array which solves the problem of writing past the end of the array. in order to stop the program from crashing i can only put the null character at the end of the array. this means that i need to increase the size of the array to accommodate for it. infuriatingly as soon as i do anything with the size variable, ie. size = size+1 the program takes a great deal longer to execute. i have no idea whats going on here so any help would be much appreciated. i have simplified the code further and the actual text file i am using on the server is included if anyone wanted to try it out. many thanks.
original post
i have written a sketch which uses the HTTPClient library to download 3 files from a server and write them to 3 SPIFFS files on an ESP32 using arduino IDE. It works fine but I am trying to improve the speed. The following code is the code which works:
#include <Arduino.h>

#include <WiFi.h>
#include <WiFiMulti.h>

#include <HTTPClient.h>

#define Serial Serial

WiFiMulti wifiMulti;

#include <SPIFFS.h>

#include "SPIFFS.h"

#define FORMAT_SPIFFS_IF_FAILED true

String url = "http://server.com";
String fileName[] = {"/file1", "/file2", "/file3"};
String fileSuf = ".dat";
String imageSuf = ".gif";
int fileIndex = 0;
int numFiles = sizeof(fileName) / sizeof(fileName[0]);

String filePath = url + fileName[fileIndex] + fileSuf;
String imagePath = fileName[fileIndex] + imageSuf;

void setup() {

  Serial.begin(115200);

  if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
    Serial.println("SPIFFS Mount Failed");
    return;
  }

  SPIFFS.format();

  ///connect to the internet
 wifiMulti.addAP("xxx", "xxx"); //work network

//    download files
    while(fileIndex < numFiles){
      getFiles(); //retreive gif image
      fileIndex++;
    }
    fileIndex = 0;

}

void loop() {

}

long timer;
int speed;

void getFiles() {

  // wait for WiFi connection
  if ((wifiMulti.run() == WL_CONNECTED)) {

    //generate paths
    filePath = url + fileName[fileIndex] + fileSuf;
    imagePath = fileName[fileIndex] + imageSuf;

    Serial.println(filePath);
    Serial.println(imagePath);

    HTTPClient http;

    Serial.print("[HTTP] begin...\n");

    // configure server and url
    http.begin(filePath);
    timer = millis(); //set timer

    Serial.print("[HTTP] GET...\n");
    // start connection and send HTTP header
    int httpCode = http.GET();
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled
      Serial.printf("[HTTP] GET... code: %d\n", httpCode);

      // file found at server
      if (httpCode == HTTP_CODE_OK) {

        // get lenght of document (is -1 when Server sends no Content-Length header)
        int len = http.getSize();

        // create buffer for read
        byte buff[2048] = { 0 };

        // get tcp stream
        WiFiClient * stream = http.getStreamPtr();

        // read all data from server
        while (http.connected() && (len > 0 || len == -1)) {

          // get available data size
          size_t size = stream->available();

          if (size) { ///
            // read up to 128 byte
            int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); //calculate size of buffer(is it full?)

            appendFile(SPIFFS, imagePath, buff, c); //addi buffer to file in flash

            if (len > 0) {
              len -= c;
            }
          }
        }

        Serial.println();
        Serial.print("[HTTP] connection closed or file end.\n");

      }
    } else {
      Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }

    speed = millis() - timer;
    Serial.println(speed); //print time taken in millis;
    http.end();

  }

}

void appendFile(fs::FS &fs, String _path, byte message[], int arr_size) {

  File file = fs.open(_path, FILE_APPEND);

   file.write(message,arr_size);

}

So thats all well and good but i experimented with how to speed it up.The following code finishes the task of downloading and writing to flash in a third of the time but because i pass the array to the print method without telling it where the buffer ends it prints 'junk' bytes on the end making the file corrupted.
My question is, why is my working method so much slower than the other method. is there any way i can get the same speed as method 2 but without printing the unwanted bytes each time? it seems like i should be able to specify this without sacrificing so much speed.
as an example of the speed file1 took 9102 ms to complete in the first approach and 3303 ms in the second. a big difference! any advice would be much appreciated, thanks!
Heres the second approach' code:
(The only changes are changing the buffer array from byte to char and using file.print(message) in the appendFile function instead of file.write(message,array_size);
#include <Arduino.h>

#include <WiFi.h>
#include <WiFiMulti.h>

#include <HTTPClient.h>

#define Serial Serial

WiFiMulti wifiMulti;

#include <SPIFFS.h>

#include "SPIFFS.h"

#define FORMAT_SPIFFS_IF_FAILED true

String path = "/test.txt";
String filePath = "http://gonadgranny.atwebpages.com/text.txt";

void setup() {

  Serial.begin(115200);

  if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
    Serial.println("SPIFFS Mount Failed");
    return;
  }

  SPIFFS.format();

  ///connect to the internet
 wifiMulti.addAP("xxx", "xxx"); //work network

      getFiles(); //retreive gif image

}

void loop() {
  readFile(SPIFFS, path);
  delay(5000);

}

long timer;
int speed;

void getFiles() {

  // wait for WiFi connection
  if ((wifiMulti.run() == WL_CONNECTED)) {

    //generate paths

    Serial.println(filePath);
    Serial.println(path);

    HTTPClient http;

    Serial.print("[HTTP] begin...\n");

    // configure server and url
    http.begin(filePath);
    timer = millis(); //set timer

    Serial.print("[HTTP] GET...\n");
    // start connection and send HTTP header
    int httpCode = http.GET();
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled
      Serial.printf("[HTTP] GET... code: %d\n", httpCode);

      // file found at server
      if (httpCode == HTTP_CODE_OK) {

        // get lenght of document (is -1 when Server sends no Content-Length header)
        int len = http.getSize();

        // create buffer for read
        char buff[2048] = { 0 };

        // get tcp stream
        WiFiClient * stream = http.getStreamPtr();

        // read all data from server
        while (http.connected() && (len > 0 || len == -1)) {

          // get available data size
          size_t size = (stream->available()) ; //make one bigger

          if (size) { ///
            // read up to 128 byte
            int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); //calculate size of buffer(is it full?)

            appendFile(SPIFFS, path, buff, c); //addi buffer to file in flash

            if (len > 0) {
              len -= c;
            }
          }
        }

        Serial.println();
        Serial.print("[HTTP] connection closed or file end.\n");

      }
    } else {
      Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }

    speed = millis() - timer;
    Serial.println(speed); //print time taken in millis;
    http.end();

  }

}

void appendFile(fs::FS &fs, String _path, char message[], int arr_size) {

  message[(arr_size-1)] = '\0'; //put in end of array

  File file = fs.open(_path, FILE_APPEND);

   file.print(message);

}

void readFile(fs::FS &fs, String path) {
  Serial.printf("Reading file: %s\r\n", path);

  File file = SPIFFS.open(path);
  if (!file || file.isDirectory()) {
//    Serial.println("- failed to open file for reading");
    return;
  }

//  Serial.println("- read from file:");
  while (file.available()) {
    Serial.write(file.read());
  }
}

add buff[size+1] = '\0' between int c... and appendFile(..., which should crop off the extra right-hand malarky when print()ed.

hi thanks for this, i used it as the basis to rewrite my code and the speed just slowed right down again. its so strange that this seemingly very simple process of checking for the end of line character is causing such an enormous increase in processing time...

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


text:
Trouble streaming audio from amazon s3 servers
I am experimenting with streaming audio from servers using an ESP32 and this library. I have been able to stream audio from every http server which i have tried but have had mixed success with https servers. I had originally wanted to stream audio from an amazon S3 server but could not get this to work. I have managed to get it to work using the google cloud servers (Both of these are https servers). Any thoughts on what might be the problem would be much appreciated. thanks.
I'm not sure if this is an appropriate forum but im not qute sure where else to post my question. thanks.

SSL decryption takes a lot of CPU power, that could be the culprit. And all streaming and ESP32 application I have seen has been just HTTP.

Hmm...ive actually now managed to get it streaming from my google cloud storage which is an https address. i was originally hoping to retrieve files from amazon aws since i am already using this for various other things but i get an error when trying to retreive files form these servers. Since the google cloud service works it can't be to do with the https protocol which i had originally thought.

Please change your question with that info.

hi, have updated question.


text:
Float mulitplication Returns ovf or -0.0 for small whole float numbers
I wrote a simple multiplication function for matrices. Originally my matrices are stored in a single array in format (row, column):
(row0, col0), (row0, col1), (row0, colN), (row1, col0), ... (rowN, col0).
so a 2x2 identity matrix would look like
float eye[4] = {1, 0, 0, 1};

In the actual function I put the 2 array matrices being multiplied into 2d arrays (easy human readable) and then do the multiplication to get the new matrix output. Then convert back to single array. I am only dealing with 3x3, 3x1, and 1x3 matrices. So my code is not be 100% compatible with every matrix possibility. I have global arrays temp3 for my 3x1 and 1x3 matrices, and temp3x3 to hold 3x3 matrices. I use a global bool squared to determine which one the new output will go to.
I get that my code is not perfect, but my question is, why do I get overflow for simple operations? My code is as follows:
#include <math.h>
#include <WString.h>

#define FLOAT sizeof(float)
void multiplyMatrixAxB(const uint8_t rows1, const uint8_t cols1, const uint8_t size1, float matrix1[], const uint8_t rows2, const uint8_t cols2, const uint8_t size2, float matrix2[]);

float K[3]; // 3x1
float dgdn[3]; // 1x3

bool squared = false;
// Temp Variable to hold matrixes
float temp3x3[9];
float temp3[3];

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Starting Matrix Test Program\n"));

  uint8_t i;
  K[0] = 1.0;
  K[1] = 2.0;
  K[2] = 3.0;

  dgdn[0] = 0.0;
  dgdn[1] = 0.0;
  dgdn[2] = 1.0;

  Serial.println(F("Matrix K setup as:"));
  for(i = 0; i < sizeof(K)/FLOAT; i++)
  {
    Serial.print(K[i]);
    Serial.print(F("\n"));
  }

  Serial.println(F("Matrix dgdn setup as:"));
  for(i = 0; i < sizeof(dgdn)/FLOAT; i++)
  {
    Serial.print(dgdn[i]);
    Serial.print(F("\t"));
  }
}

void loop()
{
  squared = true;
  Serial.println(F("\n\nA 3x1 times a 1x3 should give 3x3"));
  multiplyMatrixAxB(3,1, sizeof(K)/FLOAT, K, 1, 3, sizeof(dgdn)/FLOAT, dgdn);
  for(i = 0; i < 9; i++)
  {
    Serial.print(*(temp3x3 + i), 6);
    if(!((i+1)%3))
    {
      Serial.println();
    }
    else
    {
      Serial.print(F("\t"));
    }
  }

  Serial.print(F("\n\n"));
  Serial.println(F("End of Test"));
  while(1){delay(1000);}
}

void multiplyMatrixAxB(const uint8_t rows1, const uint8_t cols1, const uint8_t size1, float matrix1[], const uint8_t rows2, const uint8_t cols2, const uint8_t size2, float matrix2[])
{
  if(cols1 != rows2)
  {
    Serial.println(F("Multiplying Invalid Matrixes. Check ColsA and RowsB"));
    while(1){delay(1000);}
  }

  if(size1 != rows1*cols1)
  {
    Serial.println(F("rows and columns do not match size of matrix A"));
    while(1){delay(1000);}
  }

  if(size2 != rows2*cols2)
  {
    Serial.println(F("rows and columns do not match size of matrix B"));
    while(1){delay(1000);}
  }

  uint8_t row, column, k, i;
  double mat1[rows1][cols1];
  double mat2[rows2][cols2];
  double newMat[rows1][cols2];

  // place matrix1 into 2d array
  row = 0;
  for(row = 0; row < rows1; row++)
  {
    column = 0;
    for(column = 0; column < cols1; column++)
    {
      mat1[row][column] = matrix1[row*cols1 + column];
    }
  }

  // place matrix2 into 2d array
  row = 0;
  for(row = 0; row < rows2; row++)
  {
    column = 0;
    for(column = 0; column < cols2; column++)
    {
      mat2[row][column] = matrix2[row*cols2 + column];
    }
  }

  // get new array with multiplied values
  row = 0;
  for(row = 0; row < rows1; row++)
  {
    column = 0;
    for(column = 0; column < cols2; column++)
    {
      k = 0;
      for(k = 0; k < cols1; k++)
      {
        newMat[row][column] += mat1[row][k]*mat2[k][column];
      }
    }
  }

  row = 0;
  i = 0;
  // Place new matrix into single array format
  for(row = 0; row < rows1; row++)
  {
    column = 0;
    for(column = 0; column < cols2; column++)
    {
      if(squared)
      {
        temp3x3[i] = newMat[row][column];
      }
      else
      {
        temp3[i] = newMat[row][column];
      }
      i++;
    }
  }
}

Hopefully that covered everything. I have more code, but it is all mostly commented out. At worst I missed a variable declaration here, but I will mention that in the IDE it compiles fine and runs. My output looks like this:
Starting Matrix Test Program

Matrix K setup as:
1.00
2.00
3.00
Matrix dgdn setup as:
0.00    0.00    1.00

A 3x1 times a 1x3 should give 3x3
0.000000    0.000000    1.000000
ovf 0.000000    2.000000
0.000000    0.000000    3.000000

End of Test

Where does this ovf come from? I have tried printing out in the multiplication statement in the for loop the index of mat1 x the index of mat2 = "result". This will actually print out exactly what I expect to see and then my output in the main loop will be ok. What is going on? I tried some delays to see if that was the issue between calculations as well. No good.
what I mean is placing in the inner most for loop (k loop):
'''
Serial.print(mat1[row][k]); Serial.print(" x "); Serial.print(mat2[k][column]); Serial.print(" + ");
'''
And then just outside it,
'''
Serial.print(" = "); Serial.println(newMat[row][column]);
'''
I will not get any overflow in this scenario.

newMat[row][column] += mat1[row][k]*mat2[k][column];

What, precisely, at the low-level of the MCU, is that line really doing?

This covers the rowxcolumn multiplication for each new element index. The rowXcolumn needs added up to get the correct new index value for the new 3x3 matrix. First for loop iterates the number of rows that will go in the new matrix (which is rows1) , second for loop iterates the number of columns for the new matrix (which is cols2), and the last loop is what I just covered. The addition of the row by column multiplication. to go into the new indexed element.

Think of it as the summed total for the new index. I just skipped the extra variable step.

What are you asking the value to?

newMat is first declared:
double newMat[rows1][cols2];

and then updated:
newMat[row][column] += mat1[row][k]*mat2[k][column];

However, it has never been initialized. Non-static local variables are
not implicitly initialized: newMat starts its life containing whatever
garbage was in RAM at this location. You should initialize every
element to zero before you start accumulating the sum of products.

Edit: Regarding the initialization as
float newMat[rows1][cols2] = {{0},{0}};

I would expect that to initialize the whole matrix to all zeros, but my
experiment shows that it only initializes the first element of the first
two rows, and the entire third row. Initializing an array with a list
shorter than that array is supposed to initialize the other elements to
zero. However, this appears to not work recursively with the inner
arrays. I do not know whether it is a compiler bug or normal behavior.
The following, however, does work:
float newMat[rows1][cols2] = {};  // zero-initialize

Regarding the copies within multiplyMatrixAxB(), you can completely
avoid them by using pointers. For example,
double (*mat1)[cols1];

declares mat1 as a pointer to arrays of length cols1 of double.
This would be equivalent to double mat1[][cols1] within a parameter
list, and is compatible with a 2D array of width cols1 and unspecified
height. If you make this point to matrix1:
double (*mat1)[cols1] = (double (*)[cols1]) matrix1;

you can then use mat1 as a different view of matrix1: you view it
as an array of arrays of numbers, rather than a 1D array of numbers. You
can then use mat1 as you do now, and it will work by accessing the
original data, without needing an extra copy.
Using this trick, the body of multiplyMatrixAxB() can be reduced to
the following (skipping error checking):
// View the vectors as matrices.
double (*mat1)[cols1] = (double (*)[cols1]) matrix1;
double (*mat2)[cols2] = (double (*)[cols2]) matrix2;;
double (*newMat)[cols2];
if (squared)
  newMat = (double (*)[cols2]) temp3x3;
else
  newMat = (double (*)[cols2]) temp3;

// Matrix multiplication.
for (int i = 0; i < rows1; i++)
  for (int j = 0; j < cols2; j++) {
    newMat[i][j] = 0;
    for (int k = 0; k < cols1; k++)
      newMat[i][j] += mat1[i][k] * mat2[k][j];
  }

Absolutely it. I changed the newMat declaration to "float newMat[rows1][cols2] = {{0},{0}};". No issues now. Sometimes forget the little things.

I still sometimes get the -0.0. Any idea where that comes from? I should just have 0 * 0 or 0* a number in the places I'm getting it. Should just be zero. The ovf stopped though.

I placed "newMat[row][column] = 0;" above where k = 0 is. That seemed to fix it. I saw that if you just initialize one element of the multi-dimensional array, the rest that are not given a value are assigned to zero. So I did not think I needed to explicitly assign a value to each individual index.


text:
Output from LM35 temperature sensor varies wildly
I've seen other posts on this board which related to output from the LM35 sensor, but mine seem to be more 'extreme' than anything else I've seen.
I've connected the pins as is commonly suggested - left hand to 5v, middle A0, and right to GRN and used the folowing code
const int sensorPin = A0;

float sensorValue;
float voltageOut;

float temperatureC;
float temperatureF;

void setup() {

pinMode(sensorPin, INPUT);
Serial.begin(9600);

}

void loop() {

  sensorValue = analogRead(sensorPin);
  voltageOut = (sensorValue * 5000) / 1024;
  temperatureC = voltageOut / 10;

  Serial.print(sensorValue);
  Serial.print("\n");
  //Serial.print(temperatureC);
  //Serial.print("\n");

  delay(10000);
}

I commented out the temperature printing lines to avoid the error being in the conversion.
Leaving it run for a while I get the following
756.00
0.00
27.00
7.00
16.00
64.00
0.00
0.00
0.00
6.00
82.00
20.00
10.00
3.00
38.00
0.00
73.00
0.00
78.00
68.00
0.00
80.00
0.00
2.00
29.00
48.00
10.00
0.00
23.00
64.00
27.00
0.00
79.00
0.00
0.00
56.00
60.00
9.00
0.00
15.00
82.00
2.00
2.00
40.00
76.00
18.00
43.00
17.00
74.00
49.00
21.00
14.00
0.00
74.00
0.00
3.00
81.00
3.00
55.00
20.00
0.00
41.00
72.00
40.00
0.00
54.00
27.00

Our house is fairly stable in temperature, and the sensor is in a location out of anything which could drastically alter the temperature.
If anybody can suggest a reason for this I'd be grateful.

Nothing obviously bad with the code. Try replacing the LM35 with a potentiometer (pretty much same connections - one side to VCC, other side to ground, middle to A0) or just a voltage divider and see if the code works.

Thanks for the great piece of contructive thinking! I put a potentiometer onto it and it was steady as a rock, which makes me think my problem is therefore some really, really, shoddy LM35s.

Nothing wrong with your code, how do you define left hand when you holding the chip? bottom view or top view? Assuming you means TO-92 packaging.

not the problem now, but change sensorValue * 5000 to sensorValue * 5000L

Assuming the LM35 is fine you probably habe faulty connections. Most probably mixed up top/bottom view of the sensor or a connection is unreliable.

Ihcheung - 'left hand' with the writing towards me :-)
Juraj - thanks, when I get the connections sorted I'll try that
Sim Son - I'm suspecting the sensors to be honest, they were supercheap ones. I've got a different brand on order which I suspect will improve things.


text:
Can I use STL on an Arduino Uno?
I started using an Arduino Uno days ago. I'm an experienced C++ dev and I'm kind of confused.
Is the Arduino compiler different than a C++ one? What C++ version does Aruidno Uno use? Why it doesn't it support STL? Is it possible to use STL?
Also, can I configure their cpp file and use my own main function? The loop / setup thing really does annoy me. Thanks!

turn on verbose output in preferences ... examine the resulting info in the console window

is that an arduino ide things? bcs im using platform io

Yes, there are STL implementations for the Arduino Uno (check the library manager). Note that some of them are unsupported and/or outdated quite a bit. The downside of using STL on the Arduino is also that these classes may use to much memory. Because of it's very limited memory (only 2kb), dynamic memory allocation is quite risky, as memory fragmentation will quickly cause the program to crash.
The Arduino build system uses a pre-build step around the ino files that remove a lot of pain locating header files and setting up build paths from the user. This is a bit confusing at first for an experienced C++ programmer, but it simplifies things a lot, particularly when it comes to using different libraries. This build step automatically locates the include paths for all .h files referenced in the .ino. The system requires that you declare the loop() and setup() methods, but what you do with them is up to you. You can leave either of them empty, or never return from the loop function, calling into whatever main function you want to use.
As a side note: There are other C++ compiler features that are disabled or unsupported on the Uno because they would make the code to big. These include dynamic type casting using dynamic_cast<> and exception handling.

Thanks! i googled the disabled compiler features and i didnt found them, can u tell me more about them or their is only dynamic casting and exeptions?

I have found about these only, but there might be more. The compiler is actually a normal GCC (although a bit an old version) and so supports the full set of C++11 features, but the runtime library is missing some pieces.


text:
Infamous white squares for LCD display
I would like to know what I've done wrong. I configured my circuit using the "Hello world tutorial. I got the infamous white square pattern

D7 to pin 2
D6 to pin 3
D5 to pin 4
D4 to pin 5
E to pin 11

My code:
// include the library code:
#include <LiquidCrystal.h>

//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
LiquidCrystal lcd(2, 3, 4, 5, 11, 12);      // put your pin numbers here

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!");
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 0);
  // print the number of seconds since reset:
  lcd.print("hello, world!");
}

The description of the pin map does not seem to match your call legend in the lcd constructor on line.  It is difficult to tell what you have wired without the right angle on the LCD module.  In particular to see RS and RW wiring.  Complete pictures of wiring are helpful.  This would include wiring to the  Arduino, because frankly we all screw this stuff up.

it appears that in the picture you do not have the ground connected

@jsotola, it looked to me that she did, only it was a red lead.

What's connected to V0 on the display? Where's your 10K trimpot so you can adjust the contrast (by changing the voltage between 0 and Vcc) until the "infamous" white squares vanish.

@Dougie contrast is set correctly. The first line should show squares, and the second line is empty, on powerup.

Your picture does not give a clear view of the connections between the Arduino Uno and the LCD module.  However, if we are to follow your description of your connections ...

D7 to pin 2
D6 to pin 3
D5 to pin 4
D4 to pin 5
E to pin 11

... and we assume D7, D6, D5 & D4 are pins on the LCD, then we see that the code is incorrect ...
LiquidCrystal lcd(2, 3, 4, 5, 11, 12);      // put your pin numbers here

... given the LiquidCrystal description here of the syntax of the overloaded (means there are more than one pattern to the passed parameters to the identically named constructor) class ...
Syntax

LiquidCrystal(rs, enable, d4, d5, d6, d7)
LiquidCrystal(rs, rw, enable, d4, d5, d6, d7)
LiquidCrystal(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7)
LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7)

... instead, try:
LiquidCrystal lcd(?, 11, 5, 4, 3, 2);      // put your pin numbers here

... as you didn't tell us how you connected the RS line I have left that value above as a "?".  So this will not compile until you fill in the missing information.
It should be added, based on what can be seen in the picture, that a connection has been made to the LCD's RS & RW pins and no connection has been made to the LCD's E (enable) pin.  But in all the constructor's overloaded versions, there is always an E (enable) pin.  Please take a closer look at your design to determine if this is a problem.

In my case the issue was trivial: the LCD pins were not making good contact with the breadboard.
By firmly inserting them and reuploading you should be able to see "hello world!"


text:
ESP32 heap problem
I wrote a simple C++ program (just main.cpp and corresponding platform.io files & libraries) to get BME280 sensor readings. It worked fine until I decided to use good programming practices, using header files and separating the read function from main.cpp, I get a heap error, stated below:
CORRUPT HEAP: Bad head at 0x3ffb8444. Expected 0xabba1234 got 0x3ffb84c4
abort() was called at PC 0x40083b99 on core 1

ELF file SHA256: 0000000000000000

Backtrace:
0x400857f0:0x3ffb1aa0
0x40085a65:0x3ffb1ac0
0x40083b99:0x3ffb1ae0
0x40083cc5:0x3ffb1b10
0x400d90a3:0x3ffb1b30
0x400d55bd:0x3ffb1df0
0x400d5558:0x3ffb1e40
0x4008a0f1:0x3ffb1e70
0x40081dee:0x3ffb1e90
0x40083a91:0x3ffb1eb0
0x4000bec7:0x3ffb1ed0
0x400e89b5:0x3ffb1ef0
0x400d13ab:0x3ffb1f10
0x400d0f75:0x3ffb1f30
0x400d3ba9:0x3ffb1fb0
0x40086a75:0x3ffb1fd0

Rebooting...

Any ideas on that?
By the way, I also used pointers for both the function and the variable passed to it, to no avail.
I also tried a series of combinations with the libraries I am using - Adafruit BME280 and Adafruit Unified Sensor.
Going back to having all the code in one file works...
Thanks
My code:
//main.cpp
#include <sensor_readings.h>
#include <settings.h>

void refresh_readings();  // Declare in the header so that the compiler knows about it before it is called in loop()

Adafruit_BME280 bme; // I2C

void setup() {
  pinMode(LED_BUILTIN,OUTPUT);
  Serial.begin(9600);
  bool status;

  // (you can also pass in a Wire library object like &Wire2)
  status = bme.begin(0x76);
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

void loop() {
  void (*fcnPtr)(Adafruit_BME280){ &refresh_readings };
  (*fcnPtr)(bme);
  //refresh_readings(bme);
  delay(4000);
}

;platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
    Adafruit_Sensor
    adafruit/Adafruit Unified Sensor@1.1.4
    adafruit/Adafruit BME280 Library@^2.2.2
upload_port = /dev/cu.SLAB_USBtoUART
monitor_port = /dev/cu.SLAB_USBtoUART
monitor_speed = 9600

//sensor_readings.cpp
#include <sensor_readings.h>
#include <settings.h>

void refresh_readings(Adafruit_BME280 bme) {
  float f_temperature;
  float f_humidity;
  float f_pressure;
  float f_altitude;

  digitalWrite(LED_BUILTIN, HIGH);

  f_temperature = bme.readTemperature();
  f_humidity = bme.readHumidity();
  f_pressure = bme.readPressure() / 100.0F;
  f_altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

  // Temperature

  Serial.print(f_temperature);
  Serial.println(" °C");

  // Humidity
  Serial.print(f_humidity);
  Serial.println(" %");

  // Pressure
  Serial.print(f_pressure);
  Serial.println(" hPa");

  // Appx altitude
  Serial.print(f_altitude);
  Serial.println(" m");

  digitalWrite(LED_BUILTIN, LOW);
  Serial.println("------------");
}

//sensor_readings.h
#ifndef SENSOR_READINGS_H

    #define SENSOR_READINGS_H

    #include <Arduino.h>
    #include <Adafruit_Sensor.h>
    #include <Adafruit_BME280.h>

    #define SEALEVELPRESSURE_HPA (1013.25)

    void refresh_readings(Adafruit_BME280 bme);

#endif

//settings.h
#ifndef SETTINGS_H
    #define SETTINGS_H
    #define LED_BUILTIN 2   // This is valid for my devkit
#endif

There's a couple problems with your code.
void refresh_readings();  // Declare in the header so that
                          // the compiler knows about it
                          // before it is called in loop()

This is a lie! Don't tell your compiler there's a refresh_readings function that takes no arguments when you haven't defined one. Remove that line, you already have the function declaration in your header.
void (*fcnPtr)(Adafruit_BME280){ &refresh_readings };
(*fcnPtr)(bme);

This is just a very convoluted way of typing:
refresh_readings(bme);

So just use the normal function call syntax.
The main issue as far as I can tell though is that you are copying the bme object when passing it to the readings function, which is not advisable in general for this sort of object (they represent a piece of hardware that you can't really copy). That class in particular has a bunch of pointer members, a destructor that deletes them, but no copy constructor as far as I can tell, which is a bad thing.
Change your function to this signature (both in the header and the C++ file):
void refresh_readings(Adafruit_BME280& bme);
//                 pass by reference ^

And use the normal call syntax (refresh_readings(bme);).

Dear Mat, thank you VERY much for taking your time to answer to my question. It is working now. Regards, Carlos.


text:
String comparison problem
I have this callback function in my Firmata sketch. It receives a string as a character array and does something with it. The problem is, that the string is being sent to the Arduino in T\0h\0i\0s\0 form - after each character there is a \0 terminator. As you can see, my function is switching the d13 LED on if the string incoming is COMMAND. I had tried to use several comparison methods:

strcmp(myString, "COMMAND") == 1;
myString == "COMMAND";
strcmp(myString, "COMMAND\0") == 1;
myString == "COMMAND\0";
strcmp(myString, "C\0O\0M\0 M\0A\0N\0D\0") == 1;
myString == "C\0O\0M\0 M\0A\0N\0D\0";
== with saving the COMMAND to a char array variable;
strcmp with saving the COMMAND to a char array variable;
last two things with converting both the incoming and the needed to a String instance;
comparing a String instance with a directly stated "COMMAND"...

Nothing works. How can I compare the strings workably?
Full Arduino sketch:
#include <Firmata.h>

void stringCallback(char *myString)
{
  if (strcmp(myString, "COMMAND") == 1) {
    digitalWrite(13, HIGH);
  }
  Firmata.sendString(myString);
}

void sysexCallback(byte command, byte argc, byte *argv)
{
  Firmata.sendSysex(command, argc, argv);
}

void setup()
{
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
  Firmata.attach(STRING_DATA, stringCallback);
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.begin(57600);
  pinMode(13, INPUT);
}

void loop()
{
  while (Firmata.available()) {
    Firmata.processInput();
  }
}

Full code of the desktop program:
import pyfirmata, time

class CustomArduino(pyfirmata.Arduino):
    def __init__(self, port: str):
        pyfirmata.Arduino.__init__(self, port)
        self.iterator = pyfirmata.util.Iterator(self)
        self.iterator.start()

        self.add_cmd_handler(0x71, self.receiveString)

    def receiveString(self, *args, **kwargs):
        print(f'Raw: {args}\n'
              f'Received: {pyfirmata.util.two_byte_iter_to_str(args)}')

    def sendString(self, data):
        self.send_sysex(0x71, pyfirmata.util.str_to_two_byte_iter(data))

    def send_sysex(self, sysex_cmd, data=[]):
        """
        Sends a SysEx msg.
        :arg sysex_cmd: A sysex command byte
        : arg data: a bytearray of 7-bit bytes of arbitrary data
        """
        msg = bytearray([pyfirmata.pyfirmata.START_SYSEX, sysex_cmd])
        msg.extend(data)
        msg.append(pyfirmata.pyfirmata.END_SYSEX)
        self.sp.write(msg)

print('STRING TESTER\nPlease input your COM port: ', end = '')
myCom = str(input())
device = CustomArduino(myCom)

while True:
    device.sendString(input('Send: '))
    time.sleep(1)

Strange detail: my Arduino is on the COM6 COM-port. If I connect it via my program and send com6 to the arduino, the D13 LED turns on!

Comments are not for extended discussion; this conversation has been moved to chat.

As @timemage stated, strcmp returns 0 for equal. Sincerely in the provided code, while you send a message, which contents are not COMMAND, the LED will be turned on.
To get what we need, we must compare strcmp return value with 0! If it equals, then the strings match, and your suggested code is being executed:
void stringCallback(char *myString)
{
  if (strcmp(myString, "COMMAND") == 0) {
    digitalWrite(13, HIGH);
  }
  Firmata.sendString(myString);
}

the strcmp function is 50 years old and documented in many places. a fix of your code is not a useful resource on a Q&A site


text:
My DHT22 module doesn`t work at all
I had bought this DHT22 module on AliExpress. The module looks fine, but it does not work at all. I had tried lots of sketches, I tried to change the pin, I tried to change the cables, but I always have the same result:
Failed to read from DHT22 sensor!.
That's what I get if I use the standard sketch DHTtester.ino:

That's what I get if I use the standard sketch DHT_Unified_Sensor.ino:

Can you help me? Or is the module corrupted?

The sensor wants a pull-up resistor of about 10kΩ between DATA en VCC; does your module have one? What voltage are you giving it? Some don't work properly at 3.3V.

@ocrdu, yes, it has a 103 10 kΩ SMD resistor. The voltage`s 5V since the module is connected to Arduino Uno R3 via Arduino Sensor Shield V5.0.

The product page you linked to has modules of different types.
Make sure you have uncommented the matching type in the this section of the example:
// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

Also makers of these boards sometimes label them incorrectly or describe them incorrectly when selling them.  If you're unsure what you have, try them all.

I wonder that it is not my case. My sensor is truly not a DHT11, since the 11s have blue cases and mine has a white one. Though I'll  try to switch the code to the DHT21 option. Hope this one helps. But aren't the 21 and the 22 cross-compatible?

**edit: **Also, the Internet says that DHT21 has a black case, they truly cannot be messed up.

@Starter, I dunno how consistent the case is either, but it probably is useful indicator if not definitive.  I believe you are correct with respect to the DHT21 and DHT22.  Looking at the Adafruit library for them, they certainly seem to be treated the same way in every case.  If you wind up solving the problem yourself and the answer is something entirely different, you should probably make your own answer and mark it accepted.


text:
Firmata: strings sent from the computer become damaged after Arduino
I have a Python program that acts as a Firmata client. This program connects to the Arduino at a user-specified COM-port (with Firmata onboard, the sketch can be seen below), sends the user-requested string message to the Arduino, and awaits Arduino's reply. If the reply is present, the program prints it out as a list of ASCII symbol codes.
I expect the program and the sketch to work this way (block scheme is below), but the strings coming from the Arduino are damaged. They don't contain all symbols which were sent, but they contain only the first symbols in some random order, with a \0 symbol present after each character in the string. For example,

String sent to the Arduino
Received as ASCII symbol codes
Received as a string

A
(65, 0)
A\0

AB
(65, 0) where is the B?
A\0

ABC
(65, 0, 67, 0) the B lacks presence
A\0C\0

ABCD
(65, 0, 67, 0) the received data length remains the same, but B and D aren't present
A\0C\0

ABCD(10)
(65, 0, 67, 0, 40, 1, 48, 1) WHAT IS THIS?
A\0C\0(\10\1

DHTt(4)
(68, 0, 84, 0, 40, 0, 41, 1)
D\0T\0(\0)\1

Program's screenshot:

Awaited work algorithm block scheme:

Python program code:
import pyfirmata, time

class CustomArduino(pyfirmata.Arduino):
    def __init__(self, port: str):
        pyfirmata.Arduino.__init__(self, port)
        self.iterator = pyfirmata.util.Iterator(self)
        self.iterator.start()

        self.add_cmd_handler(0x71, self.receiveString)

    def receiveString(self, *args, **kwargs):
        print(f'Received: {args}')

    def sendString(self, data):
        self.send_sysex(0x71, bytearray(data, 'utf-8'))

    def send_sysex(self, sysex_cmd, data=[]):
        """
        Sends a SysEx msg.
        :arg sysex_cmd: A sysex command byte
        : arg data: a bytearray of 7-bit bytes of arbitrary data
        """
        msg = bytearray([pyfirmata.pyfirmata.START_SYSEX, sysex_cmd])
        msg.extend(data)
        msg.append(pyfirmata.pyfirmata.END_SYSEX)
        self.sp.write(msg)

print('STRING TESTER\nPlease input your COM port: ', end = '')
myCom = str(input())
device = CustomArduino(myCom)

while True:
    device.sendString(input('Send: '))
    time.sleep(1)

Arduino sketch:
#include <Firmata.h>

void stringCallback(char *myString)
{
  //The function accepts one charset.
  Firmata.sendString(myString); //send the *same* charset  back
}

void sysexCallback(byte command, byte argc, byte *argv)
{
  Firmata.sendSysex(command, argc, argv);
}

void setup()
{
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
  Firmata.attach(STRING_DATA, stringCallback); //when there is a STRING incoming to the Arduino, call 'stringCallback'
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.begin(57600);
  pinMode(13, OUTPUT);
}

void loop()
{
  while (Firmata.available()) {
    Firmata.processInput();
  }
}

How I can deal with this?

Firmata doesn't normally do something with a string (the commands are binary), so what do you want the arduino to do, actually? What you see (and why there are so many 0's in the reply) is that Firmata encodes texts, both on sending and on receiving.

@PMF, the \0s insertion wouldn't be a problem if the string returned by the Arduino contained all the characters present in the string. However, alongside with \0s insertion, not every single character present in the sent string exists in the received string.

@PMF, edited my question to make it answer your comment.

Instead of using the UTF-8 encoding,
def receiveString(self, *args, **kwargs):
    print(f'Received: {args}')

def sendString(self, data):
    self.send_sysex(0x71, bytearray(data, 'utf-8'))

it is necessary to use the pyfirmata special bytearray manipulation methods: two_byte_iter_to_str and  str_to_two_byte_iter:
def receiveString(self, *args, **kwargs):
    print(f'Received: {pyfirmata.util.two_byte_iter_to_str(args)}')

def sendString(self, data):
    self.send_sysex(0x71, pyfirmata.util.str_to_two_byte_iter(data))

You have to understand the Firmata protocol to write your own client library. The spec is here: https://github.com/firmata/protocol.
In this particular case, you need to know that data that is sent (the string in this case) can never use bit 7 of the data, since these values have special meanings. Therefore, Firmata sends every byte as two bytes, first bits 0-6 and second bit 7 as bit 0 of the next byte. Therefore, the conversion to UTF-8 is not sufficient. You need to do a two-byte-per-8-bits encoding. The same applies for the reply.

The pyfirmata client library is alright, considering that any library is going to be bad in case of its misuse, just as in my situation. In my case, the problem was on the Python program's side

Alternatively, if you want a system without Firmata's baggage of ancient MIDI constraints, like its bizarre 7-bit limit, you might consider DaqPort https://www.daqarta.com/dw_rraa.htm

your option is too hard to study in.


text:
DFPlayer Mini with its standard library does not being initialized
I have a DFPlayer Mini bought from AliExpress.
The player works correctly in standalone mode, but I am having troubles while using it with the following components:

Seeduino v4.0;
2GB Smartbuy MicroSD card.

When I try to use this standard sketch for Arduino to connect my Seeeduino V4 to the player:

if I set the serial like mySoftwareSerial(11, 10), the player's tiny LED turns on for 2 seconds, then it switches off, and after that, the board tells me the error message below (video here);
if I set the serial like mySoftwareSerial(10, 11), the player`s tiny LED switches on and remains being switched on, while the board tells me the error message below (video here):

DFRobot DFPlayer Mini Demo
Initializing DFPlayer ... (May take 3~5 seconds)
Unable to begin:
1.Please recheck the connection!
2.Please insert the SD card!

This module's image:

The circuit diagram:

simulate this circuit – Schematic created using CircuitLab
I have tried almost everything I could. I changed the filenames on my SD card, tried to use different pins, tried to use different wires..! I even tried to disconnect the speaker from the player!
I also had seen this message on the manufacturer`s forum:

I found that the solder joint on the TX pin was bridged to the SD card holder, effectively bridging the pin to the ground. Try a continuity test between the TX and ground. If they are connected you have a bad joint.
I was able to remove the excess solder and it worked fine after that. It's a medium difficulty soldering task.

Maybe, it`s my case?

The module functions as a stand-alone player.  If you find a tutorial where someone is controlling it with buttons and you have success with that, you can eliminate any concerns you may have about the sdcard, its formatting,  the sound files, and their formatting.  You can then edit your question to remove those concerns, put the actual code your using, and clear images of the actual wiring.

You didn't show, how you connected the player to the Arduino

@chrisl, edited the question.

@timemage, fixed everything I could

The comment I left suggested you try it without an Arduino, with only the button signals as a diagnostic test to be certain that your file and card formats and names are correct.  Did you in fact do this test?

The player works correctly in standalone mode, @timemage.

You can edit that fact into your question early on, since it will answer a bunch of questions straight off.

You seem to be confused about what the correct TX/RX pin wiring is.  If you aren't confused, then you should remove that from your question.  If you are still confused, then I would recommend convincing yourself by checking the TX and RX pins in question.  With nothing else attached to them, you can measure with a meter.  See what number you get.  Then connect a 1k (or so) resistor from the pin to 5V, see if the number changes significantly.  Try 1K to GND, see if it changes again.  It it doesn't change significantly you're looking at a driven pin, presumably TX; if it does, presumably RX.

Does it look like the manufacturer's connecting instructions are incorrect? Do you think that RX and TX pins are messed up on my DFPlayer or on my Seeeduino?

I don't have specific reason to think that.  I just note that you don't seem sure.  And if it were me being unsure which pin was which, I would perform that sort of test to eliminate that variable in question.

After simply switching RX and TX wires on my Seeeduino, I got the player online! This question is solved.

Please check if the RX/TX pins are messed up. In my case, simply RX and TX wires' places' switching did help!

I simply removed the test for the return value of the constructor and assumed it initialised correctly.  It then ran properly every time I started it.  I have no explanation for this, but it worked.


text:
Firmata.SendString doesn't work with specific `char` variables
I have a Firmata sketch, that accepts string messages, partitions them and sends its' parts back to a Firmata client program. My problem is certainly at the sketch's side. The problem is that Firmata.sendString(argument1) and Firmata.sendString(argument2) methods don't send anything. More information is found in the sketch's code. How can I get the sendString methods to work?
/*
 * This sketch accepts strings in the following form:
 * CMDn(arg1,arg2)
 * CMDn — command name,
 * arg1 и arg2 — unnecessary arguments.
 * Each argument's length can be from 1 to 4 characters,
 * They're saved to separate variables.
 *
 * This sketch sends back the parsed commands partially:
 * the command name, argument #1 (if present), argument #2 (if present)
 */

#include <Firmata.h>

void stringCallback(char *received) {
  //CMDn(arg1,arg2)
  //CMDn(arg1)
  //CMDn(1)
  //CMDn()
  //012345678901234
  //          11111

  //This scheme up there is just for
  //understanding the indexes of the chars in the string
  //in its various possible variations

  //Let's declare all the necessary variables
  char methodName[5];
  char argument1[5];
  char argument2[5];
  byte commaLocation = 0;

  //If the received string doesn't match the strings' syntax,
  //send an error message
  if (!(received[4] == '(' && strlen(received) <= 15)) {
    Firmata.sendString("ERR;");
    return;
  }

  //Let's take the 0-3 chars in the string and send it back.
  //It's probably the command name
  for (int i = 0; i < 4; i++) {
    methodName[i] = received[i];
  }
  methodName[4] = '\0'; //does or doesn't the compiler add the terminator automatically?
  Firmata.sendString(methodName); //send it
  //This string is being sent without problems.

  //If there is some arguments in the string,
  //it is detectable if the string char 5 is not ')'/
  if (received[5] != ')') {
    //Lent's find out if the input string has a `comma`
    //inside the parentheses. If it does, it means that
    //there are two arguments in the string.

    Firmata.sendString("46 passed");
    for (int i = 6; i < (strlen(received) - 1); i++) {
      //If there is a comma, save its' index and break the loop
      if (received[i] == ',') {
        commaLocation = i;
        break;
      }
    }

    //If a comma is not present, its location variable equals 0,
    //sincerely we just collect all the chars between the parentheses
    //to the 'argument1' variable and send it.
    if (commaLocation == 0) {
      Firmata.sendString("61 passed");
      for (int i = 5; i < ; i++) {
        argument1[(i - 5)] = received[i];
      }

      argument1[strlen(argument1)] = '\0'; //Either this is executed or not, the outcome doesn't change

      Firmata.sendString(argument1); //This very command doesn't work. It just does not send anything.
                                     //Looks like 'argument1' is empty, but I'm awfully sure that it must
                                     //not be empty. Anyway, the 'argument1' does not show up in the client
    }

    //If there is a comma present, then write chars before the comma
    //to 'argument1', and after the comma - to 'argument2'
    if (commaLocation != 0) {
      Firmata.sendString("77 passed");
      //let's write what is before the comma:
      for (int i = 5; i < commaLocation; i++) {
        argument1[i - 5] = received[i];
        Firmata.sendString("81 iterator");
      }

      //let's write what's after the comma;
      char argument2[5];
      for (int i = (commaLocation + 1); i < (strlen(received)); i++) {
        argument2[(i - (commaLocation + 1))] = received[i];
        Firmata.sendString("87 iterator");
      }

      argument1[strlen(argument1)] = '\0'; //Either this is executed or not, the outcome doesn't change
      argument2[strlen(argument2)] = '\0';

      Firmata.sendString(argument1); //Not working
      Firmata.sendString(argument2); //Not working
    }
  }
}

void sysexCallback(byte command, byte argc, byte *argv) {
  Firmata.sendSysex(command, argc, argv);
}

void setup() {
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
  Firmata.attach(STRING_DATA, stringCallback);
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.begin(57600);
}

void loop() {
  while (Firmata.available()) {
    Firmata.processInput();
  }
}

Expected output:

What I send
What I receive (excluding the debug messages, ; stands for newline)

DHTt()
DHTt

DHTt(1)
DHTt; 1

DHTt(1,2)
DHTt; 1; 2

Real output:

What I send
What I receive (excluding the debug messages)

DHTt()
DHTt as long as there are no arguments, there are no problems. But the arguments are necessary for my task

DHTt(1)
DHTt the argument are not sent

DHTt(1,2)
DHTt two arguments are not sent neither

strlen(argument1) tells you the index of the first '\0' char, so that line doesn't make sense. This would be a lot simpler if you used pointers to the char array so that you can easily set/change a start point (for example with recPtr = strchr(received, ',')) instead of skipping over offsets. Look for helpful tools in http://www.cplusplus.com/reference/cstring/

@DanDavis, isn't the cstring equivalent to the Arduino String struct, neither the character array?

Also, please pinpoint which concrete line of the code?

They're probably referring to any of the lines that take the form x[strlen(x)] ='\0';  At best x contains a valid string and this line is unless since it just puts a null terminator where one already exists.  If x is not a valid c-string, useless is the best outcome you can hope for, but not the only one.  You are going this with argument1 in two places.  argument2 in one place.  It seems like it would be good to just spend some time learning about strings outside of the context of your project.  You can play in a desktop environment and transfer over what you learn.

What does your client (the PC) do with the string? Do you use a library there or did you write the client yourself?

@pmf, everything my client program does is to accept a string provided by the user and then send it to the Arduino. More information can be found on this question.

@dandavis, strchr is making the 81 line loop lose mind. Is a pointer which strchr returns saveable to a byte variable?

Firmata.sendString does not send anything to the client in two cases:

If the message is empty;
If the message does not contain the \0 terminator in it.

In this case, while you're sending methodName, you're manually assigning the terminator to the string; and the sender works:
methodName[4] = '\0';

The only thing necessary to do to solve this argument problem is making each char variable end with a null terminator. Here you can see the solved code:
#include <Firmata.h>

//setup() and loop() won't be here, there are no changes in them

unsigned long charIndex(const char * findIn, unsigned int symbol) {
  //Find 'symbol' in char array 'findIn'. Unlike
  //strchr(), returns unsigned long or 0 if 'symbol' not found

  char * pointer = strchr(findIn, symbol);
  if (pointer != NULL) return (pointer - findIn);
  if (pointer == NULL) return 0;
}

void stringCallback(char *received) {
  //Let's declare all the necessary variables
  char methodName[5];
  char argument1[5];
  char argument2[5];
  int commaLocation = 0;
  int lasti;

  byte nullTerminatorIndex = strlen(received); //For understanding

  //If the received string doesn't match the strings' syntax,
  //send an error message
  if (!(received[4] == '(' && strlen(received) <= 15)) {
    Firmata.sendString("ERR;");
    return;
  }

  //Let's take the 0-3 chars in the string and send it back.
  //It's probably the command name
  for (int i = 0; i < 4; i++) {
    methodName[i] = received[i];
  }
  methodName[4] = '\0'; //**The compiler doesn't add terminators automatically**.
  Firmata.sendString(methodName); //send it
  //This string is being sent without problems.

  //If there is some arguments in the string,
  //it is detectable if the string char 5 is not ')'/
  if (received[5] != ')') {
    //Lent's find out if the input string has a `comma`
    //inside the parentheses. If it does, it means that
    //there are two arguments in the string.

    Firmata.sendString("46 passed");
    if (charIndex(received, ',') != 0) commaLocation = charIndex(received, ',');

    //If a comma is not present, its location variable equals 0,
    //sincerely we just collect all the chars between the parentheses
    //to the 'argument1' variable and send it.
    if (commaLocation == 0) {
      Firmata.sendString("61 passed");
      for (int i = 5; i < (nullTerminatorIndex - 1); i++) {
        argument1[(i - 5)] = received[i];
        lasti = (i - 5);
      }

      argument1[(lasti + 1)] = '\0';
      lasti = 0;

      Firmata.sendString(argument1);
    }

    //If there is a comma present, then write chars before the comma
    //to 'argument1', and after the comma - to 'argument2'
    if (commaLocation != 0) {
      Firmata.sendString("77 passed");
      //let's write what is before the comma:
      for (int i = 5; i < commaLocation; i++) {
        argument1[i - 5] = received[i];
        lasti = (i - 5);
      }

      argument1[(lasti + 1)] = '\0';
      lasti = 0;

      //let's write what's after the comma;
      char argument2[5];
      for (int i = (commaLocation + 1); i < (nullTerminatorIndex - 1); i++) {
        argument2[(i - (commaLocation + 1))] = received[i];
        lasti = (i - (commaLocation + 1));
      }

      argument2[(lasti + 1)] = '\0';
      lasti = 0;

      Firmata.sendString(argument1);
      Firmata.sendString(argument2);
    }
  }
}

Here's a simplified version of your command parser using cstrings and pointers:
void parseArgs(char * rec){
  char cmd[32];
  char arg1[32]= {0};
  char arg2[32]= {0};
  char * ptr; // this is a re-usable workhorse pointer
  char * ptrDelim; // another workhorse to split arguments

  // first copy all of it to cmd
  strcpy(cmd, rec);
  // find end of command
  ptr = cmd;
  while( isalpha(ptr[0]) ) ptr++;
  ptr[0] = '\0'; // mark end of command string

  // find first arg
  ptr = strchr(rec, '(')+1; // set ptr to char to right of open paren
  strcpy(arg1, ptr); // copy stuff after open paren to arg1:
  ptr = strchr(arg1, ')');// find max extent of arg1
  if(ptrDelim=strchr(arg1, ',')){
    ptrDelim[0]='\0'; // end arg1's string at delim
    ptrDelim++; // move right one char
    strcpy(arg2, ptrDelim); // copy stuff after comma
    arg2[strlen(arg2)-1] = '\0'; // chop off ")"
  }else{
    ptr[0]='\0';
  }//end if comma?

 Serial.println("\nGiven:" + String(rec)+";");
 Serial.println("Command:" + String( cmd )+";");
 Serial.println("Arg1:" + String( arg1 )+";");
 Serial.println("Arg2:" + String( arg2 )+";");

}

Examples:
parseArgs("CMDn()");
parseArgs("CMDn(arg1)");
parseArgs("CMDn(arg1,arg2)");

Remove the String()-having lines after you get done debugging.

In if(ptrDelim=strchr(arg1, ',')){ statement, did you mean == instead of =?

Also, what does your code do if there is no arguments in the incoming string?

@Starter: i should have wrapped the expression in parens as the compiler suggested, but it's an intentional two-fer: if the char is not present in the string it returns a falsy null-pointer, and if it finds it, it returns a truthy evaluation whilst assiging the pointer to that char's posistion.

@Starter: then they will be blank, which you can detect by if(strlen(arg1)) or if(arg1[0]) as needed.

this is not working correctly. When I input "CMDn(arg1,arg2)", I get this; if no args are present, then there is a ) in arg1; if there is only one arg, it is being recorded to arg1 along with the comma.


text:
Detect 2 wire thermostat output
I have a 2 wire thermostat. R is +24VAC, W is Heater. I have no Ground wire (C), and I cannot open the thermostat.
When the heater goes on, the thermostat internal relay gets powered and connects R and W together.
How can I detect when the heater is on from those two wires?

measure the current flowing in the wire

R -----/\/\/\---|>|----- W   ... perhaps a high value resistor in series with an LED .... it is possibe that a small amount of current could pass without activating the heater ... the LED would actually be emitter part of an optocoupler ... when the heater is off, the LED is on ... the thermostat contacts short out the LED when they close, which causes the LED to turn off

@jsotola Your opto solution worked! I have used an optocoupler in series with a 22k resistor and it does not trigger the heater. I measured the resistance between emitter and collector terminals of the optocoupler.
`Heater on  → 0 (shorted)`
`Heater off → 17Mohm`

I hope I hooked it up correctly to Arduino to detect it.

You should add a diode in reverse in parallel with the LED of the optocoupler. At the moment you're halving the power delivered to the heater. Also the optocoupler may die from the reverse voltage of AC. That is if it really is AC - you say +24VAC which makes no sense - there is no + in AC, only DC.

@Majenko added D1 but it was working anyway. The heater has a relay so it's on or off. Also added pull-down R2.

I have built the circuit but analogRead(A0) does not change :/

With checking the temperature in the room. When the contact is closed store the current temperature. Check after a minute the temperature again. If it is higher, the heater is on.

I only needed to sense the thermostat output to detect when the heater is on and log the event on my Arduino. The temperature is already checked by the thermostat. I got help in the comments and I updated the circuit which already works.


text:
Help using uint32_t? Trying to feed arduino serial from raspberry pi. Any help is very very much appreciated
So I don't know C so I'm just trying to get some very very basic code running on my arduino to send it commands over serial.
I'm feeding serial into buf
irsend.sendNEC(0x210704FB, 32)
this works but I need to read from buf instead of hardcoding for one code.
irsend.sendNEC(buf, 32) won't compile but irsend.sendNEC((uint32_t) buf, 32) will. It just doesn't do anything.
When I use
serial.print((uint32_t) buf, 32);
it prints just seemingly random letters?
I'm trying to just feed it a serial code with a language I know a little better. I can send the hex code over serial with python but I don't know the first thing about C. I don't understand why I can't just feed it a variable and have it read it as is.
here's my code
#include <IRremote.h>

char buf[80];

int readline(int readch, char *buffer, int len) {
  static int pos = 0;
  int rpos;

  if (readch > 0) {
    switch (readch) {
      case '\r': // Ignore CR
        break;
      case '\n': // Return on new-line
        rpos = pos;
        pos = 0; // Reset position index ready for next time
        return rpos;
      default:
        if (pos < len-1) {
          buffer[pos++] = readch;
          buffer[pos] = 0;
        }
    }
  }
  return 0;
}

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

IRsend irsend;

void loop() {
  if (readline(Serial.read(), buf, 80) > 0) {
    //tried to set up code to show what the arduino received and tried ways to send
    //Serial.print("You entered: >");
    //Serial.print(buf);
    //Serial.println("<");
    //doesn't seem to do anything irsend.sendNEC((uint32_t) buf, 32);
    //works but only for this one button irsend.sendNEC(0x210704FB, 32);
    //want to use irsend.sendNEC(buf, 32);
    //me trying to figure out what irsend is being fed through buf Serial.print((uint32_t) buf, 32);

  }
}

What is buf? The first two sendNEC in your question are identical but you say one compiles and one doesn't - probably a wrong copy/paste. Please [edit] your question to clarify.

serial.print(...., 32). "32" is not a valid second parameter for the serial.print() function when printing an integer value. Just leave it out or replace it with either "BIN", "DEC", "OCT" or "HEX". BTW, what is your question exactly?

I updated my post yesterday to add some clarity and show my entire code instead of just the specific function I was having a problem with. Any help is very much appreciated.

Same issue for me, but this is my solution.
Mapping beween python struct (packed data) and arduino struct is as follows:
Python              Arduino
?                   boolean
i                   int32_t or uint32_t
f                   float

Arduino Code:
// The struct we want to send over the serial connection
struct Data {
  int32_t timer;
  float value2;
  uint32_t sensor1;
  uint32_t datasize;
};
 Data data;
void setup() {
  // Initialize the serial connection
  Serial.begin(115200);
}

void loop() {
  // Create an instance of the Data struct

  data.timer = micros();
  data.value2 = 3.14;
  // read the input on analog pin 0:
  data.sensor1 = analogRead(A0);

  // Calculate the size of the struct in bytes
  size_t size = sizeof(data);
  data.datasize = size;
  // Allocate a buffer for the packed data
  uint8_t *buf = (uint8_t*)malloc(size);

  // Pack the data into the buffer
  memcpy(buf, &data, size);

  // Send the packed data over the serial connection
  Serial.write(buf, size);

  // Free the buffer
  free(buf);

  // Wait before sending the data again
  delay(10);

}

Python Code:
#
# read struct from arduino / sample code above
#

import serial
import struct

# Open the serial port
ser = serial.Serial('/dev/ttyUSB0', 115200)

# The struct we expect to receive from the Arduino
#struct Data {
#  int32_t value1;
#  float value2;
#  uint32_t value3;
#}
expFormat = "i f i i"         # Format to match arduino struct
structDataLength = struct.calcsize(expFormat)
print(structDataLength)       # RESULT IS 12

while True:
# Read the data from the serial port
# We read until we have received all the bytes for the struct

    data = b''
    while len(data) < structDataLength:
        data += ser.read(structDataLength - len(data))
    # Unpack the data into an instance of the Data struct
    val = struct.unpack('i f i i', data)

# Print the values
    print(val)

# Close the serial port
ser.close()


text:
(very new to C) I'm trying to use irsend with what I think is char* but it won't take it. How can I convert it to what it needs?
I'm attempting to use a raspberry pi to send ir codes directly to my arduino to have as simple as a C program as possible. Here's my code I've been tinkering with that leads to errors or not working if I don't specifically hardcode the hex ir signal.
#include <IRremote.h>

char buf[80];

String code = "empty";

int readline(int readch, char *buffer, int len) {
  static int pos = 0;
  int rpos;

  if (readch > 0) {
    switch (readch) {
      case '\r': // Ignore CR
        break;
      case '\n': // Return on new-line
        rpos = pos;
        pos = 0; // Reset position index ready for next time
        return rpos;
      default:
        if (pos < len-1) {
          buffer[pos++] = readch;
          buffer[pos] = 0;
        }
    }
  }
  return 0;
}

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

IRsend irsend;

void loop() {
  if (readline(Serial.read(), buf, 80) > 0) {
    Serial.print("You entered: >");
    //Serial.print(buf);
    //Serial.println("<");
    //irsend.sendNEC((uint32_t) buf, 32);
    String str(buf);
    //irsend.sendNEC((uint32_t) code, 32);
    //irsend.sendNEC(0x210704FB, 32);
    code = buf;
    delay(600);
    //Serial.print((uint32_t) buf, 32);
    Serial.print(code);
    irsend.sendNEC(buf, 32);

  }

I've left my mess on the bottom to illustrate how little I know and what I've tried. I've been trying to figure out what I'm sending it but it doesn't help that serial.print doesn't work like irsend. I'm intending to send hex codes directly and have the arduino blindly plug them into irsend.sendNEC(0x210704FB, 32); which works but when I try to put my own variable in it won't.
Very much appreciate any help! I know it'd be easy for anybody who knows a little C.
irsend.sendNEC(buf, 32); returns:
initializing argument 1 of 'void IRsend::sendNEC(uint32_t, uint8_t, bool)'
void sendNEC(uint32_t data, uint8_t nbits, bool repeat = false);
and irsend.sendNEC((uint32_t) buf, 32); doesn't throw any errors but also does not seem to do anything

when I try to put my own variable ... what variable? ... what is its value?

warning: invalid conversion from 'char*' to 'long unsigned int' [-fpermissive] irsend.sendNEC(buf, 32);

Trying to use buf. irsend.sendNEC(buf, 32); irsend.sendNEC((uint32_t) buf, 32); don't work
added two more sentences to the bottom to help clear anything up

If you are sending HEX values like 0x1234abcd from the Pi to the Arduino to send those as an IR code you first have to interpret that string data as a hexadecimal number.
That's not as simple as just casting the string since, as @timemage says, all you're doing there is casting the address of the character array.
Instead you should use strtoul() to parse the string and give you the equivalent number to what it contains.
strtoul() can convert numbers in a number of different bases, and can even work automatically.  From the Linux man page:

SYNOPSIS
unsigned long int strtoul(const char *nptr, char **endptr, int base);

And later on:

If base is zero or 16, the  string  may then include a "0x" prefix, and the number will be read in base 16; otherwise, a zero base is taken as 10 (decimal) unless the next character is '0', in which case it is taken as 8 (octal).

That means it can automatically parse 0x1234abcd as a hexadecimal number, 12345678 as a decimal number, and 052714 as an octal number (it's important to remember that one so you don't accidentally add a leading zero to a decimal number and have it parsed wrong).
So knowing all that you can now:
uint32_t code = strtoul(buffer, NULL, 0);

and code will contain the contents of buffer represented as an actual numeric variable (assuming the content can be parsed as a number).

It works! Thank you so so much. I think this is the last bit of C that I needed for this project. I appreciate the help so much. It's for remotely controlling my mother's tv while I'm at work. She has dementia and is at the point where she'll give up on the tv and sit in silence all day and her mind comes up with lots of scary thoughts by the time I'm back over to check on her. With regular cable she always winds up watching the news and in her state she feels genuine distraught and fear and spirals downward. You've helped us so so much.

The library you're using and the protocols it implements are not for sending large chunks of data.
The sendNEC function you're using is simply limited to 32 bits per transmission.  You're not going to be able to send an arbitrary length string with it, except by constructing some protocol around it that breaks the string into multiple transmissions of as much as 32 bits at a time.
Without splitting hairs about the language standard and qualifying everything to be perfectly accurate: what you're doing with your (uint32_t) cast is sending the memory address of your string over IR, which is no doubt not what you wanted nor likely particularly useful on the receiving end.
What you appear to want is something closer to IrDA.  That said, you probably could do what you want by calling sendNEC() on each character of your data in the simple case.  Better would be to send 32-bits of the string at a time since there is overhead to each transmission.  But again, these functions and protocols are designed for sending short, infrequent messages.  They were designed to be dirt simple so that they could on be implemented hardware a fraction of the power of a typical Arduino, so that they could be cheap decades ago when when they were inverted.  In an effort to be both simple and at least somewhat reliable, they sacrifice a lot of speed.


text:
Issue using micros() instead of millis()
I have two function implementations that I expected to work the same:
#define HEAD_STEP_DELAY 1000
unsigned long HeadLastMicros;
void HeadUpdate()
{
    if ((micros()>=HeadLastMicros) && ((micros()-HeadLastMicros)<HEAD_STEP_DELAY)) {
        return;
    }
    HeadLastMicros = micros();
    HeadStep(true);
}

and
#define HEAD_STEP_DELAY 1
unsigned long HeadLastMillis;
void HeadUpdate()
{
    if ((millis()>=HeadLastMillis) && ((millis()-HeadLastMillis)<HEAD_STEP_DELAY)) {
        return;
    }
    HeadLastMillis = millis();
    HeadStep(true);
}

I know that the resolution of micros() is limited to about 8us, but I figure given that I have a 1000us wait, both of the above ought to be relatively close to the same behavior. I'm driving a stepper motor from this code, and the stepper that used micros() was behaving erratically. I haven't put the scope on it yet, so I don't know for sure, but the torque was significantly less (motor stalled easily) and it sounded wonky.
I'm using an ATMEGA324A together with the MightyCore library.
Is there anything wrong with my approach? Thanks.
EDIT: I did put the scope on it after my initial post, and the period of the micros() code is approximately half the period of the millis() code.

First off, when dealing with a time system that wraps around, don't compare two times.  Compare the differences.
Second, cache your function call results if you are going to use it more than once.
Third, if you want a consistent time interval, ask for it.  Your current micros() based code could well take 1990µs on some iterations and 1001µs on others.
Fourth, don't use the current time more than once...
Do something like (not specifying millis() or micros()):
unsigned long HeadLast; /* This should be initialized somewhere (HeadStart()?),
                           as otherwise things could go weird.
                           On the Arduino platform, initializing to 0
                           may work.  On other systems, time can start anywhen.
                           This caused Microsoft Windows to have trouble after
                           being up for 49 days (started at 0), while X Windows
                           has no such issue (start anywhen).
                           */
void HeadUpdate()
{
    /* compile with -O and this will optimize to a register. */
    unsigned long now = get_time_function();

    /* We don't need to test now >= HeadLast, as time is monotonic. */
    if ((now-HeadLast)<HEAD_STEP_DELAY)) {
        return;
    }
    /* Select the time we consider this to have started at.
       This may well be before the current time. */
    HeadLast += HEAD_STEP_DELAY;
    HeadStep(true);
}