text:
Coding issue with Fast LED Multiple Colour Palettes in a State Machine
I am working on a project using the WSB2812B LED strip, with a ATmega644A using the MCUdude/MightyCore plug in (https://github.com/MCUdude/MightyCore).
I am using Fastled 3.3.3 with Ardunio 1.8.13 on Windows 10 and is using code based on "ColourWavesWithPalettes" (https://gist.github.com/kriegsman/8281905786e8b2632aeb).
This project as 2 button inputs  Solid & Palette and 2 outputs, LED DI & Mosfet gate. With the sequence being the following:

Power on and start running a set of colour palettes with fade (STANDARD_COLOUR_PALETTE). This could be anything from 5-15 colours, with transitioning colours from red to green to blue to purple to yellow... etc.

If Palette button is pressed, then change state to run 1 colour palette with fade (SINGLE_COLOUR_PALETTE) on repeat. E.G just purple with fade.

While in SINGLE_COLOUR_PALETTE state, if Palette button is pressed then change colour to another 1 colour palette e.g blue but still in the SINGLE_COLOUR_PALETTE state.

If in either "STANDARD_COLOUR_PALETTE" or "SINGLE_COLOUR_PALETTE" state and Solid button is pressed, then change state to run 1 solid colour (SOLID_COLOUR) e.g just blue with no fade.

While in "STANDARD_COLOUR_PALETTE" if Solid button is pressed, then change to another solid colour e.g Red with no fade.

While in "STANDARD_COLOUR_PALETTE" if Palette button is pressed then change state to colour palettes with fade (STANDARD_COLOUR_PALETTE).

In summary, the code is made up of 3 states with for loops and if statements. I have most of this sequence working but I am struggling a lot with step 2 & 3, as there is only 1 colour palette "Playlist" that I am trying to use as STANDARD_COLOUR_PALETTE but also trying to pull indivduial colour palettes from (SINGLE_COLOUR_PALETT).
One solution I thought of was to generate multiple separate a colour playlists one with the 5-15 colours that would fade to one another and many more that would just have the single colour palette.
How to code that into the exiting "ColourWavesWithPalettes" I used as a base?

#include "FastLED.h"
#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif

#define DATA_PIN    16
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
#define NUM_LEDS    276
#define BRIGHTNESS  250
#define SECONDS_PER_PALETTE 10 // ten seconds per color palette makes a good demo but 20-120 is better for deployment
CRGB leds[NUM_LEDS];

enum State{STANDARD_COLOUR_PALETTE, SINGLE_COLOUR_PALETTE, SOLID_COLOUR};
uint8_t State = STANDARD_COLOUR_PALETTE;
int SOLID_COLOUR_POSITION;
int SOLID_COLOUR_COUNT;
int SINGLE_COLOUR_PALETTE_COUNT;

// ten seconds per color palette makes a good demo
// 20-120 is better for deployment
#define SECONDS_PER_PALETTE 10

void setup() {
  delay(1000); // 1 second delay for recovery
  pinMode(14, INPUT); // pin #14 Solid
  pinMode(13, INPUT); // pin #13 Palette Colour
  pinMode(17, OUTPUT); // Pin #17 MOSFET gate
  digitalWrite(17,HIGH);

  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
    //.setCorrection(TypicalLEDStrip) // cpt-city palettes have different color balance //TEST THIS!!!!!!
    .setDither(BRIGHTNESS < 255);

  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);
}

// Forward declarations of an array of cpt-city gradient palettes, and
// a count of how many there are.  The actual color palette definitions
// are at the bottom of this file.
extern const TProgmemRGBGradientPalettePtr gGradientPalettes[];
extern const uint8_t gGradientPaletteCount;

// Current palette number from the 'playlist' of color palettes
uint8_t gCurrentPaletteNumber = 0;

CRGBPalette16 gCurrentPalette( CRGB::Black);
CRGBPalette16 gTargetPalette( gGradientPalettes[0] );
CRGBPalette16 gTargetPalette1( gGradientPalettes[0] );

void loop()
{

  switch (State)
  {
    case STANDARD_COLOUR_PALETTE:
        EVERY_N_SECONDS( SECONDS_PER_PALETTE ) {
        gCurrentPaletteNumber = addmod8( gCurrentPaletteNumber, 1, gGradientPaletteCount);
        gTargetPalette = gGradientPalettes[ gCurrentPaletteNumber ];
        }

        EVERY_N_MILLISECONDS(40) {
        nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 16);
        }

        colorwaves( leds, NUM_LEDS, gCurrentPalette);

        FastLED.show();
        FastLED.delay(20);

        if (digitalRead(13)==HIGH) // Colour palette pressed
        {
          delay(400);
          State = SINGLE_COLOUR_PALETTE; // Change state to single colour palettes

        }

        if (digitalRead(14)==HIGH) // Solid colour button pressed
        {
          delay(400);
          State = SOLID_COLOUR; // Change state to solid colours
          SINGLE_COLOUR_PALETTE_COUNT =++SINGLE_COLOUR_PALETTE_COUNT;
        }
    break; //End STANDARD_COLOUR_PALETTE

    case SINGLE_COLOUR_PALETTE:
//        if (SINGLE_COLOUR_PALETTE_COUNT==1)
//        {
//        EVERY_N_SECONDS( SECONDS_PER_PALETTE ) {
//        gCurrentPaletteNumber = addmod8( gCurrentPaletteNumber, 1, gGradientPaletteCount);
//        gTargetPalette1 = gGradientPalettes[ gCurrentPaletteNumber ];
//        }
//
//        EVERY_N_MILLISECONDS(40) {
//        nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette1, 16);
//        }
//
//        colorwaves( leds, NUM_LEDS, gCurrentPalette);
//
//        FastLED.show();
//        FastLED.delay(20);
//        }

        if (digitalRead(14)==HIGH) // Solid colour button pressed
        {
          delay(400);
          State = SOLID_COLOUR; // Change state to solid colours
          SINGLE_COLOUR_PALETTE_COUNT =++SINGLE_COLOUR_PALETTE_COUNT;
        }
//
//        if (SOLID_COLOUR_COUNT==1)
//        {
//          for (int i = 0; i < NUM_LEDS; i++)
//          {
//            leds[i].setRGB(255, 255, 0);
//          }
//        }
//
//        if(digitalRead(14)==HIGH)
//        {
//          delay(100);
//          SOLID_COLOUR_COUNT=++SOLID_COLOUR_COUNT;
//        }
//        FastLED.show();
//        FastLED.delay(20);
//    break; //End SINGLE_COLOUR_PALETTE

    case SOLID_COLOUR:
         if (SOLID_COLOUR_COUNT==1)
        {
          for (int i = 0; i < NUM_LEDS; i++)
          {
            leds[i].setRGB(255, 0, 0);
          }
        }

        if (SOLID_COLOUR_COUNT==2)
        {
          for (int i = 0; i < NUM_LEDS; i++)
          {
            leds[i].setRGB(0, 255, 0);
          }
        }
        FastLED.show();
        FastLED.delay(20);

        if(digitalRead(14)==HIGH)
        {
          delay(400);
          SOLID_COLOUR_COUNT=++SOLID_COLOUR_COUNT;
        }

        if(digitalRead(13)==HIGH)
        {
          delay(400);
          SOLID_COLOUR_COUNT=0;
          State = STANDARD_COLOUR_PALETTE;
        }

    break; // End SOLID_COLOUR
    }// switch end

} // Main end

// This function draws color waves with an ever-changing,
// widely-varying set of parameters, using a color palette.
void colorwaves( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette)
{
  static uint16_t sPseudotime = 0;
  static uint16_t sLastMillis = 0;
  static uint16_t sHue16 = 0;

  uint8_t sat8 = beatsin88( 87, 220, 250);
  uint8_t brightdepth = beatsin88( 341, 96, 224);
  uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
  uint8_t msmultiplier = beatsin88(147, 23, 60);

  uint16_t hue16 = sHue16;//gHue * 256;
  uint16_t hueinc16 = beatsin88(113, 300, 1500);

  uint16_t ms = millis();
  uint16_t deltams = ms - sLastMillis ;
  sLastMillis  = ms;
  sPseudotime += deltams * msmultiplier;
  sHue16 += deltams * beatsin88( 400, 5,9);
  uint16_t brightnesstheta16 = sPseudotime;

  for( uint16_t i = 0 ; i < numleds; i++) {
    hue16 += hueinc16;
    uint8_t hue8 = hue16 / 256;
    uint16_t h16_128 = hue16 >> 7;
    if( h16_128 & 0x100) {
      hue8 = 255 - (h16_128 >> 1);
    } else {
      hue8 = h16_128 >> 1;
    }

    brightnesstheta16  += brightnessthetainc16;
    uint16_t b16 = sin16( brightnesstheta16  ) + 32768;

    uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
    uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
    bri8 += (255 - brightdepth);

    uint8_t index = hue8;
    //index = triwave8( index);
    index = scale8( index, 240);

    CRGB newcolor = ColorFromPalette( palette, index, bri8);

    uint16_t pixelnumber = i;
    pixelnumber = (numleds-1) - pixelnumber;

    nblend( ledarray[pixelnumber], newcolor, 128);
  }
}

// Alternate rendering function just scrolls the current palette
// across the defined LED strip.
void palettetest( CRGB* ledarray, uint16_t numleds, const CRGBPalette16& gCurrentPalette)
{
  static uint8_t startindex = 0;
  startindex--;
  fill_palette( ledarray, numleds, startindex, (256 / NUM_LEDS) + 1, gCurrentPalette, 255, LINEARBLEND);
}

// Gradient palette "yellow_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/h5/tn/yellow.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 8 bytes of program space.

DEFINE_GRADIENT_PALETTE( yellow_gp ) {
    0, 255,255,255,
  255, 255,255,  0};

  // Gradient palette "RK_Yellow_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/lb/mp/tn/RK_Yellow.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( RK_Yellow_gp ) {
    0, 239,147,  0,
  155, 247,180,  1,
  255, 252,215,  1};

  // Gradient palette "blues_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ocal/tn/blues.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 32 bytes of program space.

DEFINE_GRADIENT_PALETTE( blues_gp ) { //Blue
    0,   0,  0, 45,
   25,   0,  0,125,
   51,   0,  0,255,
   76,   7, 12,255,
  127,   7, 55,255,
  178,   0,138,255,
  242,   0,255,255,
  255, 255,255,255};

  // Gradient palette "bhw1_33_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_33.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 16 bytes of program space.

DEFINE_GRADIENT_PALETTE( bhw1_33_gp ) { //Purple
    0,   2,  1,  8,
   94,  79,  2,212,
  140, 110, 11,197,
  255,   2,  1,  8};

// Gradient palette "Fuschia_8_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/fuschia/tn/Fuschia-8.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Fuschia_8_gp ) {//Purple
    0,  44,  4,214,
  127, 123,  1,233,
  255, 255,  0,255};

// Gradient palette "Blue_Green_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ggr/tn/Blue_Green.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 bytes of program space.

DEFINE_GRADIENT_PALETTE( Blue_Green_gp ) { //Light blue to green
    0,   0, 51,255,
   34,   1,111,255,
  144,   9,195,255,
  234,   1,225,153,
  255,   0,255, 80};

// Gradient palette "Green_3D_1_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/sd/tn/Green-3D_1.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 bytes of program space.

DEFINE_GRADIENT_PALETTE( Green_3D_1_gp ) {
    0, 103,186,106,
   42,  45,147, 48,
   84,  13,114, 14,
  127,   2, 87,  2,
  170,   0, 66,  0,
  212,   0, 23,  0,
  255,   0,  3,  0};

// Gradient palette "Mexican_flag_smooth_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ggr/tn/Mexican_flag_smooth.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 bytes of program space.

DEFINE_GRADIENT_PALETTE( Mexican_flag_smooth_gp ) {
    0,   0,255,  0,
   63,  42,255, 45,
  127, 255,255,255,
  191, 255, 55, 45,
  255, 255,  0,  0};

 // Gradient palette "Fire_2_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/icons/tn/Fire-2.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Fire_2_gp ) { //Red
    0, 255,255,  0,
  127, 255, 55,  0,
  255, 255,  0,  0};

  // Gradient palette "Orange_3D_1_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/sd/tn/Orange-3D_1.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Orange_3D_1_gp ) {// Orange
    0, 255,111, 11,
  127, 255, 92,  2,
  255, 255, 74,  1};

  // Gradient palette "bhw2_grrrrr_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_grrrrr.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 32 bytes of program space.

DEFINE_GRADIENT_PALETTE( bhw2_grrrrr_gp ) {
    0, 184, 15,155,
   35,  78, 46,168,
   84,  65,169,230,
  130,   9,127,186,
  163,  77,182,109,
  191, 242,246, 55,
  216, 142,128,103,
  255,  72, 50,168};

// Gradient palette "es_skywalker_12_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/skywalker/tn/es_skywalker_12.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 16 bytes of program space.

DEFINE_GRADIENT_PALETTE( es_skywalker_12_gp ) { // Blue
    0,  92,175,255,
   61,  20,100,255,
  153,   1, 10,170,
  255,   0,  1, 29};

// Gradient palette "es_candide_26_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/candide/tn/es_candide_26.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 24 bytes of program space.

DEFINE_GRADIENT_PALETTE( es_candide_26_gp ) { //Purple
    0, 104, 10,245,
   89, 155,  0,245,
  165, 249,  2,242,
  208, 249, 51,247,
  249, 247,180,250,
  255, 247,180,250};

// Gradient palette "cool_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/h5/tn/cool.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 8 bytes of program space.

DEFINE_GRADIENT_PALETTE( cool_gp ) { // Blue to purple
    0,   0,255,255,
  255, 255,  0,255};

// Gradient palette "green_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/h5/tn/green.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 8 bytes of program space.

DEFINE_GRADIENT_PALETTE( green_gp ) {
    0, 255,255,255,
  255,   0,255,  0};

// Gradient palette "Pink_3D_2_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/sd/tn/Pink-3D_2.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Pink_3D_2_gp ) { //Pink
    0, 244, 58,242,
  127, 222, 29,226,
  255, 201, 10,210};

// Gradient palette "GoldSunset_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/GoldSunset.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 36 bytes of program space.

DEFINE_GRADIENT_PALETTE( GoldSunset_gp ) { //Yellow and Orange
    0, 229,118,  0,
   41, 227,101,  0,
   82, 224, 86,  0,
  118, 163, 42,  0,
  124, 113, 15,  0,
  129, 167, 68,  2,
  138, 237,164, 16,
  191, 232,139,  2,
  255, 229,118,  0};

// Gradient palette "Sunset_Real_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 bytes of program space.

DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) { //Orange and blue
    0, 120,  0,  0,
   22, 179, 22,  0,
   51, 255,104,  0,
   85, 167, 22, 18,
  135, 100,  0,103,
  198,  16,  0,130,
  255,   0,  0,160};

// Gradient palette "Blue_Magenta_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Blue_Magenta.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Blue_Magenta_gp ) { //Blue purple
    0,   0,  0,255,
  127,  42,  0,255,
  255, 255,  0,255};

// Gradient palette "Red_Yellow_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Red_Yellow.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Red_Yellow_gp ) { //Red to yellow
    0, 255,  0,  0,
  127, 255, 55,  0,
  255, 255,255,  0};

// Gradient palette "Yellow_White_Magenta_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Yellow_White_Magenta.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 bytes of program space.

DEFINE_GRADIENT_PALETTE( Yellow_White_Magenta_gp ) { //Yellow to white
    0, 255,255,  0,
   63, 255,255, 45,
  127, 255,255,255,
  191, 255, 55,255,
  255, 255,  0,255};

// Gradient palette "White_Cyan_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/White_Cyan.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( White_Cyan_gp ) { //White to light blue
    0, 255,255,255,
  127,  42,255,255,
  255,   0,255,255};

// Gradient palette "Magenta_White_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Magenta_White.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Magenta_White_gp ) { //Purple to white
    0, 255,  0,255,
  127, 255, 55,255,
  255, 255,255,255};

// Gradient palette "Magenta_Cyan_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Magenta_Cyan.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 12 bytes of program space.

DEFINE_GRADIENT_PALETTE( Magenta_Cyan_gp ) { //purple to light blue
    0, 255,  0,255,
  127,  42, 55,255,
  255,   0,255,255};

  // Gradient palette "Green_Cyan_Blue_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Green_Cyan_Blue.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 bytes of program space.

DEFINE_GRADIENT_PALETTE( Green_Cyan_Blue_gp ) { //Greent to light blue
    0,   0,255,  0,
   63,   0,255, 45,
  127,   0,255,255,
  191,   0, 55,255,
  255,   0,  0,255};

// Gradient palette "rhubarb_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ocal/tn/rhubarb.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 bytes of program space.

DEFINE_GRADIENT_PALETTE( rhubarb_gp ) { //purple to red
    0, 255, 55, 45,
   76, 255,  0,  0,
  127, 188, 12, 45,
  191, 255,  0,  0,
  255, 188, 12, 45};

// Gradient palette "YlGnBu_09_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/cb/seq/tn/YlGnBu_09.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 72 bytes of program space.

DEFINE_GRADIENT_PALETTE( YlGnBu_09_gp ) { //Blue
    0, 255,255,170,
   28, 255,255,170,
   28, 210,239,102,
   56, 210,239,102,
   56, 133,209,106,
   84, 133,209,106,
   84,  41,157,117,
  113,  41,157,117,
  113,   7,121,132,
  141,   7,121,132,
  141,   1, 73,125,
  170,   1, 73,125,
  170,   1, 28, 89,
  198,   1, 28, 89,
  198,   1,  7, 65,
  226,   1,  7, 65,
  226,   1,  2, 17,
  255,   1,  2, 17};

  // Gradient palette "Oranges_09_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/cb/seq/tn/Oranges_09.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 72 bytes of program space.

DEFINE_GRADIENT_PALETTE( Oranges_09_gp ) { //Orange
    0, 255,233,207,
   28, 255,233,207,
   28, 252,203,149,
   56, 252,203,149,
   56, 249,162, 82,
   84, 249,162, 82,
   84, 249,109, 29,
  113, 249,109, 29,
  113, 249, 69,  6,
  141, 249, 69,  6,
  141, 220, 36,  1,
  170, 220, 36,  1,
  170, 167, 15,  1,
  198, 167, 15,  1,
  198,  83,  8,  1,
  226,  83,  8,  1,
  226,  41,  4,  1,
  255,  41,  4,  1};

// Gradient palette "bhw1_28_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_28.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 32 bytes of program space.

DEFINE_GRADIENT_PALETTE( bhw1_28_gp ) {// Purple blue purple
    0,  75,  1,221,
   30, 252, 73,255,
   48, 169,  0,242,
  119,   0,149,242,
  170,  43,  0,242,
  206, 252, 73,255,
  232,  78, 12,214,
  255,   0,149,242};

  // Gradient palette "bhw2_10_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_10.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 bytes of program space.

DEFINE_GRADIENT_PALETTE( bhw2_10_gp ) { //Dark green to light green
    0,   0, 12,  0,
   61, 153,239,112,
  127,   0, 12,  0,
  165, 106,239,  2,
  196, 167,229, 71,
  229, 106,239,  2,
  255,   0, 12,  0};
// Gradient palette "bhw2_11_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_11.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 bytes of program space.

DEFINE_GRADIENT_PALETTE( bhw2_11_gp ) { //Dark grren and blue mixed
    0,   0, 12,  8,
   79,   0, 55, 45,
  130,   0,136,125,
  183,   0, 55, 45,
  255,   0, 12,  8};

// Gradient palette "bhw3_01_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw3/tn/bhw3_01.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 52 bytes of program space.

DEFINE_GRADIENT_PALETTE( bhw3_01_gp ) { //Pink, to blue, to red, to yellow
    0, 255,146,228,
   25, 152, 43, 65,
   48,  36, 17, 22,
   72,   8, 34, 75,
   81,   1, 58,170,
  104,  42, 49,245,
  124,  15, 15, 95,
  150,   1,  8, 39,
  175,  98, 32, 35,
  204, 123,  9,  2,
  219, 220, 15,  2,
  237, 255, 93,  6,
  255, 244,244,  0};

   // Gradient palette "Deep_Sea_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ggr/tn/Deep_Sea.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 bytes of program space.

DEFINE_GRADIENT_PALETTE( Deep_Sea_gp ) { //Dark blue
    0,   0,  1,  2,
  148,   1,  7, 24,
  194,   2, 31, 77,
  226,   1,108,144,
  255,   0,237,235};

// Single array of defined cpt-city color palettes.
// This will let us programmatically choose one based on
// a number, rather than having to activate each explicitly
// by name every time.
// Since it is const, this array could also be moved
// into PROGMEM to save SRAM, but for simplicity of illustration
// we'll keep it in a regular SRAM array.
//
// This list of color palettes acts as a "playlist"; you can
// add or delete, or re-arrange as you wish.
const TProgmemRGBGradientPalettePtr gGradientPalettes[] = {
  GoldSunset_gp,
  //Green_3D_1_gp,
  //GoldSunset_gp,
  //bhw1_33_gp,
  //bhw1_33_gp,
  //bhw1_33_gp,
  //bhw1_33_gp,
  //Green_3D_1_gp,
  //Fire_2_gp,
  yellow_gp,
  RK_Yellow_gp,
  //yellow_gp,
  //yellow_gp,
  //blues_gp,
  //blues_gp,
  //bhw1_33_gp,
  //bhw1_33_gp,
  //bhw1_33_gp,
 Fuschia_8_gp,
  //Blue_Green_gp,
  //Blue_Green_gp,
  //Fire_2_gp,
  //Green_Cyan_Blue_gp,
  //Green_Cyan_Blue_gp,
 //Green_Cyan_Blue_gp,
  //Green_Cyan_Blue_gp,
  //Green_Cyan_Blue_gp,
  //Green_Cyan_Blue_gp,
  //Green_3D_1_gp,
  //Green_3D_1_gp,
  //Mexican_flag_smooth_gp,
  //Mexican_flag_smooth_gp,
  //Fire_2_gp,
  //Fire_2_gp,
  //bhw1_33_gp,
  //es_skywalker_12_gp,
  //Fire_2_gp,
  //es_skywalker_12_gp,
  //es_skywalker_12_gp,
  //Orange_3D_1_gp,
  //Orange_3D_1_gp,
  //bhw2_grrrrr_gp,
  //es_candide_26_gp,
  //cool_gp,
  //cool_gp,
  //green_gp,
  //green_gp,
  //Pink_3D_2_gp,
  //Pink_3D_2_gp,
  //GoldSunset_gp,
  //Green_Cyan_Blue_gp,
  //Sunset_Real_gp,
  //Blue_Magenta_gp,
  //Blue_Magenta_gp,
  //Red_Yellow_gp,
  //Red_Yellow_gp,
  //Yellow_White_Magenta_gp,
  //White_Cyan_gp,
  //White_Cyan_gp,
  //Magenta_White_gp,
  //Magenta_White_gp,
  //Magenta_Cyan_gp,
  //Magenta_Cyan_gp,
  //Green_Cyan_Blue_gp,
  //Green_Cyan_Blue_gp,
  //rhubarb_gp,
  //YlGnBu_09_gp,
  //Oranges_09_gp,
  //bhw1_28_gp,
  //bhw2_10_gp,
  //bhw2_11_gp,
  //bhw3_01_gp,
  //Sunset_Real_gp,
  Sunset_Real_gp,
 };
//
// const TProgmemRGBGradientPalettePtr gGradientPalettes[] = {
// Fuschia_8_gp,
// };

// Count of how many cpt-city gradients are defined:
const uint8_t gGradientPaletteCount =
  sizeof( gGradientPalettes) / sizeof( TProgmemRGBGradientPalettePtr );

separate the state transition and the resulting LED mode selection ... for example, at reset, go to state 0 ... in state 0, if solid pressed, goto state 1, if palette pressed, goto state 5 ... in state 1, if solid pressed, goto state 2 ... in state 2, if solid pressed, goto state 1 ... etc. etc. .............. then light LEDs according to existing state ... if state 2, light random solid color and go to state 1 ... etc. etc. ...... basically, keep the state selection by button self contained ... the LED lighting is done only on basis of the state number


text:
Rename cu.usbserial-1410 on macOS
Is it possible to rename, e.g., cu.usbserial-1410 to something else?
I have to connect multiple Arduino's and right now the order is rather important.
Being able to set a fixed name would help a lot.

Someone on https://apple.stackexchange.com/ might have more chance of answering this. It's an OS X problem not an Arduino problem.

Depending on your application, can't you ask the Arduinos for their "name" to recognize them? Relying on the PC's names of the interfaces will only work to some degree.

@thebusybee yeah, I think I probably will do that so it also works on windows

Proposal:
Instead of trying to convince the PC's OS (be it macOS, Windows, or Linux) to use a fixed name for interfaces that connect specific Arduinos, add a identifying feature to your Arduino application. Then from the PC application ask each connected Arduino for its name to identify it.

source: Stack Exchange

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

sort: votes


text:
ESP32 wifi server with multiple clients
I have a program where I configure my ESP32 as a server and it sent randomly generated data, the problem is that I can only connect 1 client at a time, what I want is that multiple clients can connect and they all receive the same information,
I put the code that I have in my ESP32 as a server
#include <WiFi.h>

const char* ssid = "SSID";
const char* password =  "Password";

char data[9];

WiFiServer wifiServer(80);

void setup() {

  Serial.begin(115200);

  delay(1000);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi..");
  }

  Serial.println("Conectado a la red WiFi network");
  Serial.println(WiFi.localIP());

  wifiServer.begin();
}

void loop() {

  WiFiClient client = wifiServer.available();

  if (client) {

    while(client.connected()) {
      //Serial.println("Client Connected");

        data[0] = random(30,50);
        data[1] = random(30,50);
        data[2] = random(30,50);
        data[3] = random(30,50);
        data[4] = random(30,50);
        data[5] = random(30,50);
        data[6] = random(30,50);
        data[7] = random(30,50);
        data[8] = random(30,50);

        client.write(data,9);
        Serial.println(int(data[0]));
        Serial.println(int(data[1]));
        Serial.println(int(data[2]));
        Serial.println(int(data[3]));
        Serial.println(int(data[4]));
        Serial.println(int(data[5]));
        Serial.println(int(data[6]));
        Serial.println(int(data[7]));
        Serial.println(int(data[8]));
        delay(1000);
    }
  }
}

I am managing the clients with python
the client code is as follows
import socket

sock = socket.socket()

host = "192.168.1.68" #ESP32 IP in local network
port = 80             #ESP32 Server Port

sock.connect((host, port))

data = ""
lista = [0,0,0,0,0,0,0,0,0]
x = 0

while True:

    data = sock.recv(1)
    #x = data.decode()
    #y = x.split("p")
    buffer = int.from_bytes(data,"big")
    lista[x] = buffer
    x = x + 1
    if x >=9:
        print(lista)
        x=0

the idea is that all clients have the same code and receive the same data
but it only allows me to connect 1 client at a time

research multicast

the esp32 Arduino WiFi library doesn't implement the print-to-all-clients functionality as other Arduino WiFi libraries do. maybe my TelnetStream library can help you.

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


text:
Can't convert string to UTF-16LE for MD5 calculation on an Arduino
TLDR
I need to convert text from a website into UTF-16LE format so that I can get the proper MD5 checksum but can't figure out how to go about doing that. This is all happening on an Arduino to log in to a router.
Background
I want to read values from a smart home device connected to a Fritz!Box router using an Arduino with an ethernet connection. The router has an open API and I'm using HTTP (EN|DE) to get the values. C++ programming is not my strong point.
I have been basing my attempts on BASH and javascript examples. For MD5 calculation I'm using tzikis' ArduinoMD5 library.
Steps
Based on the manual, you need to do the following:

Contact the router to get a challenge string (router sends XML)
Generate a response by calculating an MD5 checksum using the challenge string and password: <challenge>-<password>
Send the response, <challenge>-<response>, via POST
Receive the XLM answer from the router containing the SID
Use SID to request data or control a smart home device

I'm stuck on step 2. I have the challenge but cannot calculate the correct checksum.
The manual states:

The MD5 hash is generated from the byte sequence of the UTF-16LE
coding of this string (without BOM and without terminating 0 bytes).

Attempts
So far I can request the challenge: 70067288 for example. The reponse appears to always be alphanumeric. My password is also alphanumeric.
unsigned char* hash2 = MD5::make_hash("1234567z-äbc");
char *md5str2 = MD5::make_digest(hash2, 16);
free(hash2);
Serial.print("MD5: ");
Serial.println(md5str2);

This was my attempt at confirmation. The manual gave 1234567z as a challenge example with äbc (the a in the example does indeed have umlauts) as a password. The response shown for this example was 1234567z-9e224a41eeefa284df7bb0f26c2913e2 but my checksum from the above code was 935fe44e659beb5a3bb7a4564fba0513.
I tried "manually" generating UTF-16LE and calculating the MD5 but that didn't work either.
byte rawTest[] = {0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, 0x7a00, 0x2d00, 0xe400, 0x6200, 0x6300};
char buffer[12] = {};
unsigned char* hash2 = MD5::make_hash(&buffer[0]);
char *md5str2 = MD5::make_digest(hash2, 16);
free(hash2);
Serial.print("MD5: ");
Serial.println(md5str2);

It gave me d41d8cd98f00b204e9800998ecf8427e.
I am not entirely sure the example given was correctly calculated. Using their example in the API documentation with BASH code from the site mentioned above, I get a different answer: 1234567z-bb6e5b7c7d4d485590f4e084ad3da989.
#!/bin/bash
# -----------
# definitions
# -----------
FBF="http://192.168.178.1/"
USER="root"
PASS="äbc"
AIN="AINOFYOURFRITZDECTDEVICE"
# ---------------
# fetch challenge
# ---------------
CHALLENGE="1234567z"
# -----
# login
# -----
MD5=$(echo -n ${CHALLENGE}"-"${PASS} | iconv -f ISO8859-1 -t UTF-16LE | md5sum -b | awk '{print substr($0,1,32)}')
RESPONSE="${CHALLENGE}-${MD5}"
echo $RESPONSE

Any help getting it working is greatly appreciatet.

Working Example (with caveats)
Requirements:

Password using only characters found in ASCII
Password at least 17 characters long

The password must use only ASCII characters due to the simple way it's being converted to UTF-16LE.
I can't explain why the password must be at least 17 characters long though. My code checks the length of the actual password programmatically.
With a password at least 17 characters long I get something like this:

Challenge: 6c607ee5
Challenge Pass (26): 6c607ee5-01234567890123456
Challenge Pass Preallocation Length: 26
MD5 (UTF-16LE): 3b26241ae4aab8eaf71d5c1599932178

Any password short and I get something like this:

Challenge: 621611e1
Challenge Pass (26): 621611e1-0123456789012345�
Challenge Pass Preallocation Length: 25
MD5 (UTF-16LE): 30a163ab8a267adfbb524b2b7412e81b

Please excuse any poor coding, C++ is not my strongpoint.
void fritzboxSID() {
  EthernetClient fritzBox;
  const char* pass = "01234567890123456";  // 17 ASCII character minimum
  const char* user = "fritz3456";  // Account on router, randomly generated or user created
  const size_t passLength = strlen(pass);  // Password length
  char c;
  uint8_t xml = 0;
  char challenge[9] = {0};  // Challenge
  char challengePass[8 + 1 + passLength];  // challenge-password
  uint8_t challengeCount = 0;

  if (fritzBox.connect("192.168.200.1", 80)) {
    // Send login request
    fritzBox.println("GET /login_sid.lua HTTP/1.1");
    fritzBox.println("Host: 192.168.200.1");
    fritzBox.println("Connection: close");
    fritzBox.println();

    while (fritzBox.connected()) {
      while (fritzBox.available()) {
        c = fritzBox.read();  // Read a single character from the router response
        if (c == '>') {
          xml++;
        }
        if (xml == 5) {
            // Challenge starts after the fifth >
            if (challengeCount > 0 & challengeCount < 9) {
                // Save the challenge, character by character
                challenge[challengeCount-1] = c;
                challengePass[challengeCount-1] = c;
            }
            challengeCount++;
        }
        Serial.print(c);  // Print HTTP response
      }
    }
    challengePass[8] = '-';
    for (size_t i = 0;i < passLength; i++){
      // Copy password into the combined challenge-password string
      challengePass[i+9] = pass[i];
    }

    // Show challenge and pass, checking lengths
    //      If the strlen(challengePass) doesn't equal the preallocation length then the MD5 will be incorrect
    Serial.println("");
    Serial.print("Challenge: ");
    Serial.println(challenge);
    Serial.print("Challenge Pass (");
    Serial.print(strlen(challengePass));
    Serial.print("): ");
    Serial.println(challengePass);
    Serial.print("Challenge Pass Preallocation Length: ");
    Serial.println(8 + 1 + passLength);

    // Convert to UTF-16LE (only works for standard ASCII characters)
    const size_t length = strlen(challengePass);
    char buffer[2*length];
    for (size_t i = 0; i < length; i++) {
      buffer[2*i] = challengePass[i];
      buffer[2*i+1] = 0;
    }

    // Generate MD5
    unsigned char* hash = MD5::make_hash(buffer, 2*length);
    char *md5str = MD5::make_digest(hash, 16);
    free(hash);
    Serial.print("MD5 (UTF-16LE): ");
    Serial.println(md5str);
  } else {
    Serial.println("Cannot connect to 192.168.200.1");
  }
}

If it helps, the response from the router for the initial login request is this:
HTTP/1.1 200 OK
Cache-Control: no-cache
Connection: close
Content-Type: text/xml
Date: Fri, 16 Sep 2022 08:21:27 GMT
Expires: -1
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; connect-src 'self'; font-src 'self'; frame-src https://service.avm.de https://help.avm.de https://www.avm.de https://avm.de https://assets.avm.de https://clickonce.avm.de http://clickonce.avm.de http://download.avm.de https://download.avm.de 'self'; img-src 'self' https://tv.avm.de https://help.avm.de/images/ http://help.avm.de/images/ data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; media-src 'self'

<?xml version="1.0" encoding="utf-8"?><SessionInfo><SID>0000000000000000</SID><Challenge>621611e1</Challenge><BlockTime>0</BlockTime><Rights></Rights><Users><User last="1">fritz3456</User><User>UserName</User></Users></SessionInfo>

The iconv option -f ISO8859-1 looks suspicious. Are you sure you are using this old, legacy character set? Your bash script gives me the expected output if I remove that option. 2. Can you manage to have an ASCII-only password? If so, the translation to UTF16LE would be practically trivial.

Good find. My password is ASCII only. The example provided in the documentation was not. How would you convert it to UTF-16LE in Arduino C++ in that case? I still need to programmatically convert the challenge as well. Thanks for the quick answer.

byte rawTest[] = {0x3100, 0x3200,..... this is not doing what you think it does. I'm assuming you weren't looking for a creative way to fill your array with 0x00 values.  Probably you meant 0x31, 0x00, 0x32, 0x00,.....

Good to know. If I ever get around to expanding the code from ASCII passwords I'll try that out. Let's see how hard it is to complete the login process and get data first.

You have to convert the string "<challenge>-<password>" to
UTF-16LE. If the whole string is plain ASCII, the conversion is trivial:
you just have to add a zero byte after each ASCII byte.
// ASCII string to be hashed.
const char* text = "1234567z-abc";  // umlaut removed

// Convert to UTF-16LE.
const size_t length = strlen(text);
char buffer[2*length];
for (size_t i = 0; i < length; i++) {
    buffer[2*i] = text[i];
    buffer[2*i+1] = 0;
}

// Compute and print the hash.
unsigned char* hash2 = MD5::make_hash(buffer, 2*length);
char *md5str2 = MD5::make_digest(hash2, 16);
free(hash2);
Serial.print("MD5: ");
Serial.println(md5str2);

Note that I use the two-parameter version of MD5::make_hash() in order
to pass the length of the buffer. The one parameter version of this
method would stop at the first zero byte.

Edit: Regarding your extended question (the new section “Working
Example”), this is a problem completely unrelated to the previous one.
It is about string termination.
In C and C++, strings are arrays of characters terminated with a NUL
ASCII character (numeric value zero). The terminating NUL is not part of
the string per se, but it should be stored in the array holding the
string. String literals are interpreted by the compiler as
NUL-terminated arrays of characters. Every function that expects a
string as an input expects it to be NUL-terminated.
In this particular instance, you failed to NUL-terminate
challengePass. When this array is given to strelen(), this function
scans the memory until it finds a zero byte. If that zero byte happens
to be right after the end of the array, your code will work as expected.
Otherwise, any non-zero byte coming after challengePass in memory will
be interpreted as being part of the string. The program behavior is
unpredictable, because you do not know what will be stored in memory
right after challengePass.
The solution is to NUL-terminate the string. Start by allocating one
more byte:
char challengePass[8 + 1 + passLength + 1];  // challenge-password

Then, right after copying the password, add a zero byte to terminate the
string:
challengePass[8 + 1 + passLength] = '\0';  // terminate the string

Note that '\0' means “the character with numeric value zero”.
Alternatively, you can terminate the string right after adding the dash,
then use strcat() to concatenate the password. strcat() will take
care of terminating the string:
challengePass[8] = '-';
challengePass[9] = '\0';  // temporarily terminate the string
strcat(challengePass, pass);  // append password

That actually works, but for some reason I generate text it fails. If I then manually type the new challenge and same password into const char* text... it gives the correct MD5.
C++ character/string operations are profoundly confusing.

@Jeremy: What do you mean by “I generate text it fails”? In what manner does it fail? I should not matter whether the text is typed in the source or generated programmatically.

I tried posting code in a comment but it was a complete mess.
const char* pass = "myPassword";
const size_t passLength = strlen(pass);
char challenge[9] = {0};  // Challenge
char challengePass[8 + 1 + passLength];  // challenge-password

Using the ethernet module I then read in the XML from the router, copying it character by character to challenge and challengePass. After that I tried strcat to build the challenge-password string to feed into the MD5 function. The MD5 was always wrong though. Is it because strcat adds a null-terminator to the end?

@Jeremy: The question about string concatenation in your last comment is: 1. Unrelated to the current question, which is about ASCII → UTF16-LE conversion. 2. Impossible to answer without seeing how you are actually trying to concatenate the strings.

This entire question is in the context of assembling a string to not just generate any MD5 checksum but the correct MD5 checksum. The particulars are very important. I understand this is Stack Exchange and tangential questions should be asked on their own. Now to see if I can figure out the other steps required. Thanks again for the help. If I, or someone else, figures out the password length caveat I'll update the solution.

@Jeremy: See extended answer.

I don't know if it's worth changing anything in the answer for this, but it may be good to know that you seemingly have the option of using a lower level set of features (MD5_CTX, MD5Init, MD5Update, MD5Final) that provide for avoiding the temporary buffer, dynamic memory allocation, and concatenation. The various concatenations, including those of 0x00 being done to up convert ASCII to UTF-16LE, become separate calls to MD5Update.

Thanks for the tip. I'm slowly in the process of converting it all to useable functions. Once I get to optimization I'll give it a shot. No doubt there are plenty of ways to optimize my C++ code.


text:
How to properly set CS for SPI applications on Arduino Due
I needed SPI with CPOL=1 and CPHA=1. I read, that I could achieve this via SPI_MODE3. Further, I read to put the CS low and CS high code after SPI.beginTransaction(...) and before SPI.endTransaction() (See official doc). But the result does not look right.
Minimal example program:
void setup() {   // put your setup code here, to run once:
    pinMode(52, OUTPUT); // CS high
    digitalWrite(52, 1);
}

void spi_transfer() {
    uint8_t buffer[] = {0, 0};

    delayMicroseconds(1);
    SPI.begin();
    SPI.beginTransaction(SPISettings(SPI_BAUD, MSBFIRST, SPI_MODE3));
    delayMicroseconds(1);

    digitalWrite(52, 0); // CS Low
    delayMicroseconds(1);

    SPI.transfer(buffer, 2); // Data
    delayMicroseconds(1);

    digitalWrite(52, 1); // CS High
    delayMicroseconds(1);

    SPI.endTransaction();
    SPI.end();
    delayMicroseconds(1);
}

void loop()
{
  spi_transfer();
}

In yellow we see the CS signal (I use pin D52). In lila we see the clock signal.
To my understanding, this is not CPOL=1, as the Clock signal is low when the chip select goes low.
To my understanding, this is CPOL=0.
Is there a proper way to handle this? Setting CS outside of the begin/end Transfer would make the whole concept a bit superfluous.

it looks like the clock idles high ... it goes low before data transfer and returns to idle high after the transfer ... the second clock edge(rising) latches data


text:
IF statement to run even if the requirement isn't met anymore
I have built a flasher for the headlamps on my race car. Whilst it works when I hold the switch down, if I release the switch and the circuit is closed my IF statements requirements are no longer met and it stops flashing.
Is there a way to have it continue to run the IF statement (but only once) even after I've let go of the switch and the requirement is no longer met?
Thanks in advance.
CODE:
#define trig A3

const int flash = 3; //D3
const float mVc = 4.67; //reference voltage
float counts = 0;
float mV = 0;

void setup() {
  Serial.begin(115200);
  pinMode(flash, OUTPUT);
}

void loop() {
  counts = analogRead(trig);
  //counts = 255;
  Serial.println(String(counts));

  mV = (counts*mVc) / 1000;
  Serial.println("Input Voltage: " + String(mV) + "v");

  //delay(1000);

// voltage will need to be changed to matched output voltage when on car
  if (counts > 10) {
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(1000);
  }
}

EDIT:
TL;DR Don't use voltage dividers to power the Nano.
When using a voltage divider to power the Nano (I know, I know) the below solution didn't fix the issue. I thought it may be due to the voltage dropping when the Nano supplies the 5vo to the mosfet but I'm not sure why holding the switch would stop that from happening. Regardless I swapped to a linear voltage regulator and then it started to flash, "Hurrah!" -- almost.
With the regulator in it was running the code constantly. I decided to print the runcount and I got a number over 35,000, meaning it would run the flash 5 times for >35,000 times. Although curious as to what would happen when it reached zero, I decided to go back to my original code and...now it works.
So I guess the lesson is: Even if you can calculate the drop off, don't run your Nano on a voltage divider.

I have checked the answer below as the solution, although it didn't fix my issue there is no reason it shouldn't have worked and it may be useful to someone else.

why are you using analog I/O?

You could define an int runcount = 0 variable at the top. Then change your loop logic to something like
if (counts > 10) {
  runcount = 2;
}

if (runcount-- > 0) {
  //flashy flashy
}

The effect is, that while button is pressed and counts > 10, runcount is set to two. Every time we check the runcount, it is decreased by 1. While the button is pressed, runcount is resat to 2. If you let go of the button, runcount will be 1 at the start of the if condition check. It will be compared to 0, condition will be true, and it will then be decreased to 0 and the if section will be executed one last time. Using another number than 2 will change the number of extra runs.

Thank you, I will give this a go tomorrow and then all that is left is the "easy" bit of fitting it to the car. :)


text:
Upload to board with no USB connection
I have a Spark Fun Pro Micro (ATmega32U4) without a USB connection (it was broken off at an earlier point) that I want to use to duplicate a prototype running on another Pro Micro.
How can I upload a sketch to an Arduino without a USB connection?

The best solution is to solder back the connector or to buy a new board.
Ways to use a board with ATmega32u4 without USB for development are:

ICSP programming
upload over a serial bootloader.

Both require additional hardware.
For ICSP upload you need a programmer device. After configuring it, select the programmer in Tools menu and you can use "Upload using programmer" from the sketch menu. It is even possible to create a custom board definition which will use "Upload using programmer" with the "Upload" button from the toolbar.
To make serial upload possible you will need and USB-to-TTL-Serial adapter and  Optiboot compiled for the 32u4. To burn the bootloader you will need an ICSP programmer or a second Arduino to use with the Arduino as ISP sketch.

Use a programmer, such as one based on CH341A that has pins broken out for CLK, CS, MOSI, MIOS [sic], GND, 3.3V, and connected those to pins on the Pro Micro as follows:

Programmer    Pro Micro
CLK-----------15 (SCK)
CS------------RST
MOSI----------16 (MOSI)
MIOS----------14 (MISO)
GND-----------GND
3.3V----------RAW

It doesn't appear that the programmer is supported in the Arduino IDE, so I grabbed chavrprog.
And ran the command $ sudo ./chavrprog -d mega32u4 -a s ~/Arduino/test/test.ino.leonardo.hex

I see. The upload program implements the protocol. This is a very nonstandard solution for the problem in the question.


text:
Robot car not working
My robot car won’t respond to my command. The code below worked before however, this time there is no response. I’ve tried experimenting with the code in the first while loop. I’ve tried different code from other projects similar to this. I’ve played with the schematics however, nothing seems to work.
This is my code:
#include <SoftwareSerial.h> // TX RX software library for bluetooth
#include <Servo.h> // servo library
Servo myservo1, myservo2, myservo3; // servo name
int bluetoothTx = 10; // bluetooth tx to 10 pin
int bluetoothRx = 11; // bluetooth rx to 11 pin
int motorOne = 4;
int motorOne2 = 5;
int motorTwo = 6;
int motorTwo2 = 7;
int enA = 3;
int enB = 2;
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

//initial motors pin

char command;
char Value;

void setup()
{
  myservo1.attach(2); // attach servo signal wire to pin 9
  myservo2.attach(8);
  myservo3.attach(12);

  //Setup usb serial connection to computer
  Serial.begin(9600);
  //Setup Bluetooth serial connection to android
  bluetooth.begin(9600);
}
void loop()
{
  while (bluetooth.available() > 2) {
    Value = bluetooth.read();
    Serial.println(Value);
  }

  if ( Value == 'F') {
    // Robo Pet Run Forward
    digitalWrite(enA, 255);
    digitalWrite(enB, 255);
    digitalWrite(motorOne, HIGH);
    digitalWrite(motorOne2, LOW);
    digitalWrite(motorTwo, HIGH);
    digitalWrite(motorTwo2, LOW);
  } else if (Value == 'B') {
    //Robo Pet Run Backward
    digitalWrite(enA, 255);
    digitalWrite(enB, 255);
    digitalWrite(motorOne, LOW);
    digitalWrite(motorOne2, HIGH);
    digitalWrite(motorTwo, LOW);
    digitalWrite(motorTwo2, HIGH);
  } else if (Value == 'L') {
    //Robo Pet Turn Left
    digitalWrite(enA, 255);

    digitalWrite(motorOne, LOW);
    digitalWrite(motorOne2, LOW);
    digitalWrite(motorTwo, HIGH);
    digitalWrite(motorTwo2, LOW);
  } else if (Value == 'R') {
    //Robo Pet Turn Right

    digitalWrite(enB, 255);
    digitalWrite(motorOne, HIGH);
    digitalWrite(motorOne2, LOW);
    digitalWrite(motorTwo, LOW);
    digitalWrite(motorTwo2, LOW);
  } else if (Value == 'S') {
    //Robo Pet Stop
    digitalWrite(motorOne, LOW);
    digitalWrite(motorOne2, LOW);
    digitalWrite(motorTwo, LOW);
    digitalWrite(motorTwo2, LOW);
  }

  //Read from bluetooth and write to usb serial
  if(bluetooth.available()>= 2 )
  {
    unsigned int servopos = bluetooth.read();
    unsigned int servopos1 = bluetooth.read();
    unsigned int realservo = (servopos1 *256) + servopos;
    Serial.println(realservo);
    if (realservo >= 1000 && realservo <1180) {
      int servo1 = realservo;
      servo1 = map(servo1, 1000, 1180, 0, 180);
      myservo1.write(servo1);
      Serial.println("Servo 1 ON");
      delay(10);
    }
    if (realservo >= 2000 && realservo <2180) {
      int servo2 = realservo;
      servo2 = map(servo2, 2000, 2180, 0, 180);
      myservo2.write(servo2);
      Serial.println("Servo 2 ON");
      delay(10);
    }
    if (realservo >= 3000 && realservo <3180) {
      int servo3 = realservo;
      servo3 = map(servo3, 3000, 3180, 0, 180);
      myservo3.write(servo3);
      Serial.println("Servo 3 ON");
      delay(10);
    }

  }
}

I’m using this app:
https://play.google.com/store/apps/details?id=com.giumig.apps.bluetoothserialmonitor&hl=en&gl=US
And here are the schematics:

Is Serial.println(Value); printing what you expect?

test if everything is wired correctly ... write simple code that tests each motor ... test servo

@timemage When it worked before, the app would print a series of numbers and then the letters. It only prints command if my Nano is connected to the computer.

@jsotola I've tested the motors and servos individually and controlled them with potentiometers before moving on to Bluetooth. I've also tested the Bluetooth module with a simple blink command on the app and it works fine.

I've tested the motors and servos individually and controlled them with potentiometers before moving on to Bluetooth ... that was before ... test them now ... run one of the motors for a second in setup()

What get from that is that it Serial.print(Value); used to do what you expect, which is not what I'm asking. It's broken now. What is it doing now?

@jsotola i tested each motor again with just a simple sketch and they both work fine.

@timemage  Now nothing is printed on the Serial monitor even if the Arduino Nano is plugged to the computer.

A annotated schematic as you have wired it in place of your fuzzy frizzy picture would be a big help. Besure it shows all connections including power and ground.  Include links to the hardware devices that give "Technical" information.

@timemage
Your answer was part of the solution!
Thank you very much! In the first while loop I switched it from bluetooth.available > 2 to bluetooth.available > 0 and then switched the signs of the TX and RX. Now the robot car is responding and running. However it won't turn left even though both motors work fine.

In short, among whatever other problems you might have, you've wired your TX and RX connections backwards according to your diagram and code.
Swap them either in hardware or in software.

According to the documentation:
SoftwareSerial var_name(rxPin, txPin)

SS Operation

RX

TX

You've constructed your SoftwareSerial object as:
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

SS Operation
Pin Variable

RX
bluetoothTx

TX
bluetoothRx

Defined your pin variables to these pins:
int bluetoothTx = 10; // bluetooth tx to 10 pin
int bluetoothRx = 11; // bluetooth rx to 11 pin

SS Operation
Pin Variable
Arduino Pin

RX
bluetoothTx
10

TX
bluetoothRx
11

Connected them as:

SS Operation
Pin Variable
Arduino Pin
BT Operation

RX
bluetoothTx
10
RX

TX
bluetoothRx
11
TX

So, you have them backwards. Connecting their RX (inputs) which is is harmless but not helpful and connecting their TX (outputs) which may damage something.
In case this isn't clear, the RX and TX on the HC-05 are labeled from its perspective and not from the perspective of the Arduino. Except for some things like an old external modem, RX and TX on device are nearly always labeled from that device's perspective.

A variable name like bluetoothTx can be confusing if you're not sure which thing is doing the transmitting. Is this the pin number for transmitting to Bluetooth or the pin that will be connected to the Bluetooth transmitter (in other words, for receiving)?
In some cases I just describe the situation in the variable name:
static const int PIN_SOFTSERIAL_RX_TO_BLUETOOTH_TX = 11;
static const int PIN_SOFTSERIAL_TX_TO_BLUETOOTH_RX = 10;
/// ...
SoftwareSerial bluetooth(
  PIN_SOFTSERIAL_RX_TO_BLUETOOTH_TX,
  PIN_SOFTSERIAL_TX_TO_BLUETOOTH_RX
);

I dunno that I'd go with a name quite that long, but you get the idea.
I'm swapping them in software here, leaving your physical connections as they were in the diagram mostly because I don't feel like redrawing your diagram. Though, if it were my project I would swap the wires (and defined pin numbers above), because the convention is to have SoftwareSerial receive on 10 just like hardware receives on pin 0 and to have SoftwareSerial transmit on 11 just like hardware transmits on pin 1; in order words, keeping the relative order of the pin numbers.
So this is what you have with the above code:

SS Operation
Pin Variable
Arduino Pin
BT Operation

RX
PIN_SOFTSERIAL_RX_TO_BLUETOOTH_TX
11
TX

TX
PIN_SOFTSERIAL_TX_TO_BLUETOOTH_RX
10
RX

Transmitters connected to receivers.
If you get confused build your own table and make sure your variable names make sense.
This has nothing to do with our question really, but: Most Arduino users, new ones anyway, are better off with an Arduino that has connectivity that displaces the need for SoftwareSerial. A minimal change from the Nano for what you're doing is a Micro or Pro Micro board. That board has native USB support which it uses to send "Serial" to the computer. That leaves the one actual hardware serial peripheral on the (Pro) Micro available for you to to connect to HC-05 (or whatever). There are a pile of options, including ones that just do Bluetooth also (without need of HC-05). Anyway, there are lots of ways to not use SoftwareSerial.


text:
On ATtiny84, why does delay() stop working properly when RadioHead ASK is used?
When I call the delay() function on the ATtiny84 micro, it delays for the expected time, until I call the init() function on an RH_ASK object. After this, the micro seems to freeze.
#include <RH_ASK.h>
RH_ASK driver();

void setup() {
    delay(100); // works ok
    driver.init();
    delay(100); // freezes a long time (or maybe forever?)
}

After reading the source code, RH_ASK.cpp, I found a commented out macro.
// RH_ASK on ATtiny8x uses Timer 0 to generate interrupts 8 times per
// bit interval. Timer 0 is used by Arduino platform for millis()/micros()
// which is used by delay()
// Uncomment the define RH_ASK_ATTINY_USE_TIMER1 bellow, if you want to use
// Timer 1 instead of Timer 0 on ATtiny
// Timer 1 is also used by some other libraries, e.g. Servo. Alway check
// usage of Timer 1 before enabling this.
// Should be moved to header file
//#define RH_ASK_ATTINY_USE_TIMER1

In other words, the default behaviour of RadioHead ASK init() is to use Timer 0, which causes delay() (which uses millis()/micro()) to behave incorrectly.
To fix: Tell RadioHead ASK to use Timer 1. Because the RH_ASK_ATTINY_USE_TIMER1 macro is in the source and not the header (for now), you have to modify the actual RadioHead ASK source file, RH_ASK.cpp*. Un-comment the line #define RH_ASK_ATTINY_USE_TIMER1 which will use Timer 1 instead of Timer 0. Re-compile your code, and delay() should start working properly again.
* RH_ASK.cpp can be found in %USERPROFILE%\Documents\Arduino\libraries\RadioHead on Windows, if you installed RadioHead via the Arduino IDE library manager.


text:
Unable to upload code to my digispark ATtiny 85 after upgrading bootloader
I've just received my digispark ATtiny85 (model B, I believe). I'm using Pop_OS for my PC, had a bit of a headache getting the arduino IDE recognising the device but after some trial and error I got there.
When uploading a sketch I would then get erase errors and if I recall correctly it was error -71.
I couldn't work it out but found out that my boards came with v1.6 of the micronucleus firmware. So I upgraded to the latest which is v2.6. Now when I upload a sketch however the output looks like the following
Sketch uses 718 bytes (11%) of program storage space. Maximum is 6012 bytes.
Global variables use 9 bytes of dynamic memory.
Running Digispark Uploader...
Plug in device now... (will timeout in 60 seconds)
Warning: device with unknown new version of Micronucleus detected.
This tool doesn't know how to upload to this new device. Updates may be available.
Device reports version as: 2.6
Warning: device with unknown new version of Micronucleus detected.
This tool doesn't know how to upload to this new device. Updates may be available.
Device reports version as: 2.6

I don't have a clue what to try next as everything feels like it should be at a working point. Not sure how to decipher "Updates may be available". I'm using the latest arduino IDE, with the digistump board manager url and using the latest micronucleus firmware for the board.
I tried to re-flash the firmware to v2.4 just on the off chance that the firmware was too new to be supported in arduino IDE but I received the same error as above but with just a different version number reported.

You have version 1.6.7 (current) of the digistump board package installed?

@timemage yes I believe I do. This json file http://digistump.com/package_digistump_index.json
With Digispark (Default - 16.5mhz) as the board chosen,

"my boards came with v1.6 of the micronucleus" I'm guessing you meant 1.06. So far as I've been able to tell 1.6 was never a version.

It seems the latest version (1.6.7) of the Digispark board support package is quite old, older than I'd have guessed. And so it does come with an old Micronucleus programming tool. The tool appears to compare the major version number of the firmware as found in the USB device version. And since the Micronucleus tool in the 1.6.7 package is expecting nothing newer than major version 1, major version 2 of the firmware is not going to work with it.
You have a couple of options.
Reprogram old firmware (1.11)
You already seem familiar with burning .hex files. So, if you want to use the latest official Digispark board support you need to burn the hex file for Micronucleus version 1.11.  I replicated your error, but using an OLIMEXINO-85-ASM which is highly similar to the Digispark but may not be identical.  After programming micronucleus-1.11.hex the board worked with the official Digispark board support package.
Use ATTinyCore
However, you could also just abandon that old official package and use ATTinyCore which does come with a Micronucleus bootloader new enough to program the Digispark board with Micronucleus 2.6. I tested that as well.
Patch a new Micronucleus tool into your old official support package
You can replace the Micronucleus tool with a newer one in your arduino15/packages/digistump/tools/micronucleus/2.0a4 directory. Incidentally, I have no idea where the 2.0a4 comes from, but it is not indicative of a Micronucleus 2.0 in any way that I can tell.
For testing I put the 2.6 firmware on the board, specifically the t85_default.hex file, and stole the Micronucleus tool out of the latest ATTinyCore board packages tools directory, by renaming the existing file an symbolically linking in the other one:
$ pwd
/home/user/.arduino15/packages/digistump/tools/micronucleus/2.0a4
$ ls
launcher  micronucleus
$ mv -iv micronucleus micronucleus.backup
renamed 'micronucleus' -> 'micronucleus.backup'
$ ln -s ~/.arduino15/packages/ATTinyCore/tools/micronucleus/2.5-azd1b/micronucleus
$ readlink micronucleus
/home/user/.arduino15/packages/ATTinyCore/tools/micronucleus/2.5-azd1b/micronucleus
$

And that works as well.


text:
ESP32: Is the networking stack running in separate thread? Can you safely block task executed from loop() for longer time? (>3s)
With ESP8266 there is a requirement to not block the CPU execution for longer than few ms and then yield to networking stack and internal functions that are executed after each iteration of loop(). If you block CPU for too long, network will misbehave. If you block it for longer than ~3 seconds SWDT resets the MCU.
Now with ESP32 you have 2 CPU cores and RTOS running in the background that has full multithreading support. Is the Arduino framework for ESP32 taking advantage of this? Is the whole "user program" running as separate task besides the network and system stack? Would blocking the CPU in main loop cause similar problems as ESP8266?
From xPortGetCoreID() we can see that both setup and loop run always from core 1, not core 0, so I assume that user program is by default pinned to core 1 and network stack runs on core 0? Can someone confirm that?
This is just hypothetical question, I am just curious about internal ESP32 architecture and Arduino implementation, not making anything specific.

In the Arduino IDE you can select on which core the user program shall run, but yes, the default is 1.

@PMF ok, but does that mean the network stack is running separately in core 0, or is it done in same "everything in 1 thread" way as in ESP8266?

As far as I know it runs on its own thread (the ESP32 uses a FreeRTOS kernel in the back). I have a project where I run quite expensive operations on the "user" core while a connection is maintained automatically. It should be easy to test this, shouldn't it?


text:
Strange problems driving an Optocoupler (PC123) with a Nano
I'm having some strange issues getting a Nano to drive a PC123 optocoupler properly.
What I'm trying to do: In the real world, I need to press a button ONCE, and have the device that I'm connecting this too, see FIVE quick button presses... (Input 1 press, and Output 5 presses, at the timing I set in the code). I am using a mix of LED "Blinking / Flashing" code to do what I need.
My connection of the Opto seems fine. It works perfectly if I run this "BLINK" code: (With the PC123 optocoupler connected to Pin13):
// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(200);                       // wait for a while
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(200);                       // wait for a while
}

When I run this, the Optocoupler turns ON and OFF as I need, and the device I am controlling is happy, but it obviously runs forever as I have no counters or anything.. (This proves my hardware is good at this point!)
But, when I try this following code, with the exact same hardware circuit, the output goes HIGH as soon as I ground Pin2, and it stays HIGH! It holds the optocoupler ON and there is no ON/OFF or "blinking or flashing". BUT, it only does this when the OPTO is connected (there is load) on the Nano output. If I disconnect the Opto, the Pin13 LED will flash as expected. And my code seems to work fine (on the on-board Pin 13 LED).
VERY interestingly and very strangley though, when the "power-up" Pin 13 LED flashes (i.e- when you power cycle the Nano, or press the reset button) this will trigger the Opto ON/OFF perfectly! But when the code starts to run, via my Pin 2 input switch, with the Opto connected to the Nano, the output locks HIGH again! What the!?
int ledPin = 13;   // LED is connected to digital pin 13
int switchPin = 2;   // switch connected to digital pin 2
int switchValue;   // a variable to keep track of when switch is pressed
int counter = 0;

void setup()
{
      pinMode(ledPin, OUTPUT);   // sets the ledPin to be an output
      pinMode(switchPin, INPUT);   // sets the switchPin to be an input
      digitalWrite(switchPin, HIGH);   // sets the default (unpressed) state of switchPin to HIGH
}

void loop()   // run over and over again
{

    switchValue = digitalRead(switchPin);   // check to see if the switch is pressed
      if ((switchValue == LOW) && (counter <= 1)) {   // if the switch is pressed then,
          for(int ii = 0; ii <= 5; ii++)   // 7 = 4 flashes, 5 = 3 flashes, etc
      {
          digitalWrite(ledPin, !digitalRead(ledPin));
          delay(100); // Length of the flashes in ms
          counter++;
      }
    }
      if (switchValue == HIGH)
      //if ((switchValue == HIGH) && (counter > 2))
      {
           counter = 0;
           delay(100); // Debounce

      }
}

I have tried filtering capacitors, diodes, resistance, pull-ups, pull-downs, everything I can think of and I am at a loss. Can anyone help me out? I'm thinking its a code issue (because I am an Arduino noob - please be gentle!), or a maybe a deficiency in the hardware of the Nano? FYI, I have done all of this on different Input and Output pins with the same results.
Any help would be greatly appreciated!

you have digitalWrite(switchPin, HIGH) which activates the internal pull-up resistor

Yes, but isn't that required for my LOW switch (D2) to trigger the code? Otherwise it will float?
Also, it works with no load (with the Opto not connected). It will flash the Pin 13 led fine. But with the load on the output (Pin13 - or any other pin I choose), the output goes HIGH when the code runs and stays HIGH.

I tried changing digitalWrite(switchPin, HIGH)  to LOW, and also removed it all together. Regardless of this, triggering the D2 input always results in the same thing...
Is the counter code correct? Maybe its getting stuck in the counter loop somehow??

just a note about comments in code ..... digitalWrite(switchPin, HIGH);   // sets the default (unpressed) state of switchPin to HIGH ... the comment is misleading ... while it is technically true, because it enables the pullup resistor, a beginner programmer may think that digitalWrite(switchPin, LOW); sets a default state of the pin to LOW

why aren't you using the same code to blink the led in the second program? ... the second program makes an assumption about the state of the output pin ... set the state instead of inverting previous state

Thanks for the reply. I understand the pull-up code and the pin state as a result. That's all ok.
Why am I not using the blink code that works? Because it doesn't do what I need.  I'm a new and I don't know how to make that code start and stop using a momentary button input, and to have it only flash five times when I do press that button...
If you can help me with that I would be most grateful. Cheers

Thank you @DrG for your excellent reply! I really appreciate the time you have taken on this. I will answer your questions here:

What am I trying to do? I am adding the Nano to a Ham Radio Transceiver, that can change frequency (via button presses on the microphone) in only 1kHz, or 10kHz frequency steps. What I am doing here, is by adding this Nano to the microphone button circuit, and selecting the "1kKz" step option, I will get a "5kHz" step! This is great for searching for SSB signals quicky (1kHz is slow, 10kHz is too big and you miss some!). So, I press 1 time, the radio will step 5 times. This is the purpose of my project. :)

How have I wired it up? Exactly the same as you have shown, and I have also used both D13 (not recommended as you said, and D10 (as you have used in your proposed answer).

Your code is great, and I really like that it will use D13 to show what it's doing on the LED, and use D10 to drive the Opto. GREAT!

Now - here is the crazy part... Even with your code, and the exact circuit (other than my PC123 vs your 4N25 (I have 4N35's here too), I get exactly the same problem I had before! As soon as the Nano drives the Opto, regardless of the GPIO I configure, it locks HIGH! The D13 LED flashes as expected, but D10 goes high and never goes low again, until a reboot or power cycle...
I now believe that even my original code is fine (not the best way to do it, but still functional) but my NANO is faulty! It's an "ELEGOO NANO" clone. And I think it's the issue!!!
Your input is not wasted as I will use your code, it is much better than mine! :) I am going to get a new NANO and try this again, and now I am pretty confident that with a new Arduino, this will work! I will report back and let you know how it goes.
Best regards,
Pez

I confess that I am not sure what you are trying to do, but I have an idea and I hope this helps. First, there are several Nanos and not all of them are AVR-based. I used an OLD Nano clone and even had to select the ATMega 328P (old bootloader) - it's been a while. I also used a 4N25 opto [this could make a difference, look at the data sheet for your device)..
You have not shown exactly how you have things wired up. Let's assume that it is like this - and I DO NOT think it is a good way of doing things (bear with me), and

Using this code, it works exactly as it should.
int ledPin = 13;
int switchPin = 2;
int nflashes=10;
void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT);
}

void loop() {
  if ( digitalRead(switchPin)==HIGH) {
  for (int i = 0; i < nflashes; i++) {
      digitalWrite(ledPin, !digitalRead(ledPin));
      delay(100);
    }
    while (digitalRead(switchPin) == HIGH); // wait until switch is released
  }
}

The opto turns on with D13 lighting the added LED and the onboard LED also turns on. Note that the onboard LED is dimmer because you are driving TWO LEDs ; the onboard one attached to D13 and the LED inside the opto and you have no current limiting resistor on the opto LED. I'm not sure if you have it wired this way but if so, in my view, it is not a good way of doing things.
Apart from that, think about what happens when you hit reset...my guess is that the ATMega sets all GPIO to input AND the boot loader initializes the onboard LED to an output and apparently flashes that LED - I am guessing and have not gone through the code. I notice that with the above scheme, I see both the new LED and the onboard LED flash once briefly on reset, as I would expect.
Hooking up the switch as I have shown (pulled to ground) will eliminate any problems from floating states during a reset. It will only be read HIGH when you press the switch after you initialize the GPIO.

I would put the opto on a separate GPIO like this:

...and using this slightly modified code
int ledPin = 13;
int switchPin = 2;
int optoPin=10;
int nflashes=10;
void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT);
  pinMode(optoPin, OUTPUT);
}

void loop() {
  if ( digitalRead(switchPin)==HIGH) {
  for (int i = 0; i < nflashes; i++) {
      digitalWrite(ledPin, !digitalRead(ledPin));
      digitalWrite(optoPin, !digitalRead(optoPin));
      delay(100);
    }
    while (digitalRead(switchPin) == HIGH); // wait here until switch is released
  }
}

Everything works fine and the new LED does not flash during a reset and nothing gets stuck.
I wish you had show exactly what connections you made and I apologize if I missed some point.
Again, hope it helps.

Thank you @DrG for your excellent reply!  I will answer your questions in a new "answer" because I can't type enough characters here...


text:
Simulate pin behaviour based on PulseView recording
I have a bunch of PulseView recordings from an existing device. Currently to verify if my Arduino handles the input properly I always use the real device. However it would be great if I could somehow test my code with existing recordings. I am using platform.io. Perhaps there is some test framework that can mock a pin based on a recording? For example when I start the test, pin 8 should be high for 10μs then low for 7 and so on. Is there some framework to mock such things?

that is not an arduino specific question ... it applies to any microcontroller ... if you are talking about a hardware solution, then ask at https://electronics.stackexchange.com/questions

I've never heard of such a test framework and I doubt there is one, at least for hobbyists. Such a framework would need to include a lot of hardware to accommodate all the possible electrical test cases and also a rather complex software to control the hardware according to user input. So it is not really practical to have a general testing framework.
But you can build your own for your specific case. Using another Arduino and outputting the requested pulses should not be too difficult. In the simplest version just some digitalWrite()s and some delayMicroseconds() calls.


text:
Replace char based on user input
I am developing a hangman game on tinyduino(tinycircuits) and I am currently stuck on how to properly replace a char based on user input within a for loop. My current code does actually replace the correct underscore(blank), if a user inputs a correct letter.
As per the game hangman, it will print out a series of blanks(in my case, underscores) based on number of letters, that serve as placeholders for the correct letter and will reveal the letter only if a user inputs a correct letter.
However, whenever a user inputs another correct letter (after inputting a correct letter prior), my program creates another 'line' and replaces the underscore in that new line instead.
For example, say the word to guess is kotlin. If user inputs 'k', my console shows me:
k_____

The output above is still correct.
But, when the user inputs another letter, say 'o' which is also correct, the result I get is:
k______o____

To further re-emphasize, now if a user inputs 't', I would get:
k______o______t___

What do I need to modify in my code in order to replace the underscores in the original line whenever a user enters a correct letter? Below is my current code.
if (k == 1) { // Str1 is "kotlin"
    display.setCursor(10,50);
    length = strlen(Str1);

    String user_input = String(phone_input);
    String word = String(Str1);

    for (i = 0; i < length; i++) {
      word[i] = '_';

      if (user_input == "k") {
        word[0] = 'k';
      }

      if (user_input == "o") {
        word[1] = 'o';
      }

      if (user_input == "t") {
        word[2] = 't';
      }

      if (user_input == "l") {
        word[3] = 'l';
      }

      if (user_input == "i") {
        word[4] = 'i';
      }

      if (user_input == "n") {
        word[5] = 'n';
      }

      display.print(word[i]);
      SerialMonitorInterface.print(word[i]);
    }
  }

why does it have to be in a for loop?

print your code on paper ... get a pencil ... go through your code step by step ... make notes about values of variables ... it may help you discover why your code does not work as you think that it does

The logic of your code seems confused. The loop doing word[i]='_'; belongs the initialization phase, which is performed only when a new game is started. The tests on user_input belong to the regular “play” phase. I suggest you move the “initialize a new game” logic into its own function, and think carefully about what kind of event should trigger the start of a new game. Also, you print() the current guess without erasing the previously printed ones, and without moving the cursor to the next line. Try println() instead.

@EdgarBonet could you elaborate more about println() and moving the cursor?

@jsotola it is in a for loop because every instance a user inputs a correct character, the for loop should replace the specific index's underscore. Is there a better method to approach this?

Attention  spoiler (If it's ok for you just to enhance it to a playable version by enhancing the shortcuts! )
If you want to replace single characters in a word, String and
std::string is way too much overhead. Use good old char [] instead.
const char* result { "kotlin" }; // shortcut
const size_t size = 6; // shortcut

char guess[size+1]; // The guessed intermediate result

const byte wrongMax = 22;
byte wrong = 0; // number of wrong guesses

void setup() {
  for (char& c : guess) c='_';
  guess[size] = 0;

  Serial.begin(9600);
  Serial.println(guess);
}

void loop() {
  if (strcmp(result,guess)== 0) {
    Serial.println("Got it !"); while (1){} // Stop, reset required
  }
  if (wrong >= wrongMax) {
    Serial.println("Failed !"); while (1){} // Stop, reset required
  }

  int c = Serial.read();
  if (c >= 'a' && c <= 'z') {
    // shortcut: only lower characters allowed
    byte p;
    for (p=0; p < size; p++) {
       if (c == result[p] && guess[p] == '_') {
         // found a new correct one
         guess[p] = c;
         break;
       }
    }
    if (p == size) {Serial.print( ++wrong ); Serial.println( " wrong guesses");}
    Serial.println (guess);
  }
}


text:
Send a 2d PROGMEM array over SoftwareSerial
I have a 2d array:
const byte messages_for_measurement[2][8] PROGMEM =
{
  { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
  { 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 },
};

I want to send one of these sub-array over software serial.
Initially, this produced junk data:
swSerial.write( messages_for_measurement[0], sizeof(messages_for_energy_meter[0]) );

Then I learned about pgm_read_byte_near() and pgm_read_word(). I tried every combination but I did not get this to work:
swSerial.write(pgm_read_byte_near(pgm_read_word(messages_for_measurement[0]))), sizeof(pgm_read_byte_near(pgm_read_word(messages_for_measurement[0])));

and
swSerial.write(pgm_read_byte_near(&pgm_read_word(messages_for_measurement[0]))), sizeof(pgm_read_byte_near(pgm_read_word(&messages_for_measurement[0])));

and
swSerial.write(char(pgm_read_byte_near(pgm_read_word(messages_for_measurement[0])))), sizeof(char(pgm_read_byte_near(pgm_read_word(messages_for_measurement[0]))));

and
swSerial.write(char(pgm_read_byte_near(pgm_read_word(&messages_for_measurement[0])))), sizeof(char(pgm_read_byte_near(pgm_read_word(&messages_for_measurement[0]))));

How can I send the sub-array over serial, when the 2d array is in PROGMEM?

The write() method from SoftwareSerial (which is inherited from the
abstract Print class) does not support printing PROGMEM-based binary
buffers. The print() method does have some PROGMEM support, but it is
limited to printing NUL-terminated character strings, and is meant to be
used with the F() macro. You could coerce this method into printing
your data, but this would require you to add a null byte at the end of
each inner array, and the trick would break if you ever have to send a
null byte.
Also, the pgm_read_stuff() macros cannot read an array at a time. You
could do achieve this with memcpy_P(), but that would require
allocating an array in RAM. I think the simplest solution here is to get
the bytes from the flash one by one with pgm_read_byte():
const byte *message = messages_for_measurement[0];
size_t size = sizeof messages_for_measurement[0];
for (size_t i = 0; i < size; i++) {
    swSerial.write(pgm_read_byte(&message[i]));
}

Note that the first line does not attempt to access the array data: it
only copies into message the address of the first byte: this is the
decay-to-pointer semantics.


text:
Getting “Open the GPS power failure” on module SIM808
I tried to get the gps coordinates with this program:
#include <DFRobot_sim808.h>
#include <SoftwareSerial.h>

#define PIN_TX    8
#define PIN_RX    7
SoftwareSerial mySerial(PIN_RX,PIN_TX);
DFRobot_SIM808 sim808(&mySerial);//Connect RX,TX,PWR,

//DFRobot_SIM808 sim808(&Serial);

void setup() {
  mySerial.begin(9600);
  Serial.begin(9600);

  //******** Initialize sim808 module *************
  while(!sim808.init()) {
      delay(1000);
      Serial.print("Sim808 init error\r\n");
  }

  //************* Turn on the GPS power************
  if( sim808.attachGPS())
      Serial.println("Open the GPS power success");
  else
      Serial.println("Open the GPS power failure");

}

void loop() {
   //************** Get GPS data *******************
   if (sim808.getGPS()) {
    Serial.print(sim808.GPSdata.year);
    Serial.print("/");
    Serial.print(sim808.GPSdata.month);
    Serial.print("/");
    Serial.print(sim808.GPSdata.day);
    Serial.print(" ");
    Serial.print(sim808.GPSdata.hour);
    Serial.print(":");
    Serial.print(sim808.GPSdata.minute);
    Serial.print(":");
    Serial.print(sim808.GPSdata.second);
    Serial.print(":");
    Serial.println(sim808.GPSdata.centisecond);
    Serial.print("latitude :");
    Serial.println(sim808.GPSdata.lat);
    Serial.print("longitude :");
    Serial.println(sim808.GPSdata.lon);
    Serial.print("speed_kph :");
    Serial.println(sim808.GPSdata.speed_kph);
    Serial.print("heading :");
    Serial.println(sim808.GPSdata.heading);
    Serial.println();

    //************* Turn off the GPS power ************
    sim808.detachGPS();
  }

}

But when I run it, I'm getting the "Open the GPS power failure" message.
I think my gps is working because If I try with AT commands Im getting a response:
 AT+CGPSSTATUS?
+CGPSSTATUS: Location 3D Fix

OK
AT+CGPSINF=0
+CGPSINF: 0,2543.585143,10018.826326,483.868110,20221118025902.000,19,10,0.509509,266.733459

OK

I even tried to get NMEA info and parse that in python, I was getting my actual position so it seems is working properly.
The problem comes when I tried to use DFRobot_sim808 library or TinyGps libraries.
I would like to know what might be causing this issue or is there a way to parse NMEA info coordinates without using a library?

this may help ... https://www.gpsworld.com/what-exactly-is-gps-nmea-data/

are you at a library in Monterrey?

Yeah... I was there. How did you get the location? I know I gave them but I want to know how you translate or parse that raw gps info

I parsed the NMEA sentence ... 2543.585143,10018.826326 is the latitude and longitude ... 25 degrees 43.585143 minutes ... 100 degrees 18.826326 minutes .... that is 25.72641905, 100.3147721 degrees .... 25°43'35.1"N 100°18'53.2"W
https://goo.gl/maps/2UV2g2qouJ2uWhJaA

Okey I understand that you are parsing coordinates in DDDMM.MMMM to a more readible format. But how are you doing that? Are you using a formula, a software, a library or what? I want to know that because I need to capture that info through code

pencil and paper  ... convert degrees and minutes to decimal degrees

Okey, you really gave me enough to work with. Thank you :)


text:
power 12v solenoid from DC jack of Arduino Uno
I was wondering if it is possible to power up a 12V solenoid valve from the DC jack of the Arduino Uno, provided that I'm powering the Arduino from the same jack:

the Arduino is kind of irrelevant to the question ... make a Y cable instead of soldering to the connector ... cut the existing cable and splice a pigtail into it

i would use a dc jack Y adapter instead of splicing the wire, but whatever's clever should suffice.

Thank you everyone for your comments, I was just afraid of frying my setup

Sure, that's the same as if you were directly soldering a second plug to your power supply. Just make sure the power supply delivers enough current for your solenoid (the power used by the Arduino will be comparably negligible).


text:
When a button is pressed, it interferes with TFT screen
I'm trying to build a simple device to monitor my heart rate. The components are the following:

A TFT 2.8" LCD screen to display relevant information for the user.
3 buttons for the user to interact with the device.
A PPG sensor to acquire the user's heartbeat.
An Arduino Uno.
A breadboard to connect the components.

The setup of the device looks like this:

which is connected in the following way:

I haven't included the TFT screen here in the drawing of the circuit because I'm using Tinkercad and they don't have it in the components. The screen has the following ports:

The code that I'm using is the following:
// Heartbeat sensor libraries
#define USE_ARDUINO_INTERRUPTS true
#include <PulseSensorPlayground.h>

// TFT screen libraries
#include <TFT.h>  // Arduino LCD library

// Heartbeat sensor variables
const int PulseWire = 0; // PulseSensor WHITE WIRE connected to ANALOG PIN 0
int Threshold = 550; // Determine which Signal to "count as a beat"
PulseSensorPlayground pulseSensor; // Creates an instance of PulseSensorPlayground

// TFT screen variables
#define cs   10
#define dc   9
#define rst  8
TFT TFTscreen = TFT(cs, dc, rst);

// Button variables
const int buttonUp = 2;
const int buttonDown = 3;
const int buttonOk = 4;

#define DELAY 1.0/64.0

void setup() {

   Serial.begin(9600); // For Serial Monitor

   pulseSensor.analogInput(PulseWire);
   pulseSensor.setThreshold(Threshold);

   pulseSensor.begin(); // Start heartbeat sensor
   TFTscreen.begin(); // Start TFT screen

   drawScreen(); // Draw content of the screen

   // Buttons
   pinMode(buttonUp, INPUT);
   pinMode(buttonDown, INPUT);
   pinMode(buttonOk, INPUT);
}

bool buttonUpPrev = false;
bool buttonDownPrev = false;
bool buttonOkPrev = false;

void loop(){

   if(buttonUpPrev == HIGH && digitalRead(buttonUp) == LOW){
      Serial.println("button up");
   }

   if(buttonDownPrev == HIGH && digitalRead(buttonDown) == LOW){
      Serial.println("button down");
   }

   if(buttonOkPrev == HIGH && digitalRead(buttonOk) == LOW){
      Serial.println("button ok");
   }

   buttonUpPrev = digitalRead(buttonUp);
   buttonDownPrev = digitalRead(buttonDown);
   buttonOkPrev = digitalRead(buttonOk);

   //Serial.println(pulseSensor.getLatestSample());

   delay(DELAY);
}

My problem is that when I press one of the buttons, the TFT screen flickers, as if less voltage gets to the screen. Also, sometimes I see "button down" in the Serial Monitor when nothing is being pressed. Overall the device works, but I wonder if I made a mistake.
My question is: Is there a problem with the cabling of this device? I've studied Computer Science and I just know the basics of electronics. Thank you!

try using internal pullup resistors ... remove the external pulldown resistors and connect the switches between the data pins and ground

Also instead of delay(1.0/64.0);, use delayMicroSeconds(15);.


text:
ESP32-S3 - HttpClient only returns 200 status code no JSON payload data
I have a ESP-S3 board and am trying to get JSON data from our server. I am using the following code (see below) as a basis for mine.
This code works. If I change
http://jsonplaceholder.typicode.com/comments?id=10

to
http://mywebsite.com
I do get the html for our server's main page.
If I then change
http://mywebsite.com

to
http://mywebsite.com/profiles

I get status code 200 but no JSON.
I type http://mywebsite.com/profiles in a browser it returns the JSON or if I use postman and do a GET on http://mywebsite.com/profiles it returns JSON.
It sounds like this issue posted a couple of years ago:
esp32 http client response only 200 didn't receive the data after that
Any insight as to what I am doing wrong would be greatly appreciated.
#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "yourNetworkName";
const char* password =  "yourPassword";

void setup() {

  Serial.begin(115200);
  delay(4000);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");

}

void loop() {

  if ((WiFi.status() == WL_CONNECTED)) { //Check the current connection status

    HTTPClient http;

    http.begin("http://jsonplaceholder.typicode.com/comments?id=10"); //Specify the URL
    int httpCode = http.GET();                                        //Make the request

    if (httpCode > 0) { //Check for the returning code

        String payload = http.getString();
        Serial.println(httpCode);
        Serial.println(payload);
      }

    else {
      Serial.println("Error on HTTP request");
    }

    http.end(); //Free the resources
  }

  delay(10000);

}

how big is the JSON response? There's not a huge amount of room for large responses. Try a smaller response and see if you still get nothing.

I can't reproduce what you experienced, your code works perfectly and I got the json back. The only difference is that I'm using an ESP32 instead of ESP32S3. Maybe you try to swap the lines between String payload = http.getString(); and Serial.println(httpCode);, this might provided sufficient time for payload to be received completely.

dandavis - that is definitely something to check. thank you for the suggestion. hcheung - the above code works for me too. It fails when I use my server.

dandavis - that was the issue. a smaller response size worked.


text:
Having a problem with DS18B20 getTempC using an array containing the addresses of the sensors
I have been struggling with this and am at a total loss as to why its not working.
Here is my program:
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is Arduino pin A0
#define ONE_WIRE_BUS A0

// Setup a oneWire instance
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// Define array for holding all the sensors addresses and load addresses.
//======================================================================
DeviceAddress SensorAddr [13] =
                 {
 ( 0x28, 0xAA, 0x30, 0x41, 0x38, 0x14, 0x01, 0x14 ), // Sensor 1
 ( 0x28, 0xAA, 0x24, 0x31, 0x38, 0x14, 0x01, 0xDF ), // Sensor 2
 ( 0x28, 0xAA, 0xE4, 0x30, 0x38, 0x14, 0x01, 0x72 ), // Sensor 3
 ( 0x28, 0xAA, 0xD4, 0xC2, 0x38, 0x14, 0x01, 0x80 ), // Sensor 4
 ( 0x28, 0xAA, 0x6C, 0xDA, 0x38, 0x14, 0x01, 0xD5 ), // Sensor 5
 ( 0x28, 0xAA, 0xCA, 0x39, 0x38, 0x14, 0x01, 0xBB ), // Sensor 6
 ( 0x28, 0xAA, 0x75, 0x28, 0x38, 0x14, 0x01, 0x2C ), // Sensor 7
 ( 0x28, 0xAA, 0xFB, 0xB2, 0x38, 0x14, 0x01, 0xBF ), // Sensor 8
 ( 0x28, 0xAA, 0x0F, 0x3A, 0x38, 0x14, 0x01, 0xC3 ), // Sensor 9
 ( 0x28, 0xAA, 0x6F, 0x26, 0x38, 0x14, 0x01, 0xF8 ), // Sensor 10
 ( 0x28, 0xFF, 0x64, 0x1E, 0x1E, 0x6A, 0x74, 0xF1 ), // Sensor 11
 ( 0x28, 0xFF, 0x64, 0x1E, 0x1E, 0x7D, 0x29, 0x55 ), // Sensor 12
 ( 0x28, 0xFF, 0x64, 0x1E, 0x1E, 0x73, 0xAC, 0x3A )  // Sensor 13
                   };

void setup(void)
{
  Serial.begin(9600);
  sensors.begin();

//Test first Sensor Address  - This works
//=======================================

  byte Sensor1Test[8] = { 0x28, 0xAA, 0x30, 0x41, 0x38, 0x14, 0x01, 0x14};
  Serial.print("Test Sensor 1: ");
  float tempTest = sensors.getTempC( Sensor1Test );
  Serial.print(tempTest, 2);
  Serial.print("\xC2\xB0"); // shows degree symbol
  Serial.print("C");
  Serial.println();
}

void loop(void)
// Get all temperatures - This does not work??
//============================================

{
  sensors.requestTemperatures();
  for (int S =0; S<13; S++)
      {
        Serial.print("Sensor # "); Serial.print(S+1); Serial.print(": ");
        float tempC = sensors.getTempC(SensorAddr [S]);
        Serial.print(tempC,2);
        Serial.print("\xC2\xB0"); // shows degree symbol
        Serial.print("C");
        Serial.println();
        delay(1000);
      }
 Serial.println();
}

please, no pictures of text ... delete the picture and add the text

Go through the tutorial at https://lastminuteengineers.com/multiple-ds18b20-arduino-tutorial. Try using their code for reading multiple sensors by address (or index, but you are trying to read by address).  Try doing the read loop the way they are doing it and using uint8_t arrays - it can't hurt. Let us know how that goes please.

that is not how this site works ... please post the updated code in an answer and explain how the problem was solved ... rolled back your edit

The DeviceAddress internally is defined as an array of uint8_t (see definition:
typedef uint8_t DeviceAddress[8];

That is, each address is an array itself.
DeviceAddress Sensor1 = { 0x28, 0xAA, 0x30, 0x41, 0x38, 0x14, 0x01, 0x14 };

So if you have 13 DeviceAdrress, you are dealing with a two-dimension array, and you need to declare it as:
#define NUMBER_OF_SENSORS 13
DeviceAddress SensorAddr [NUMBER_OF_SENSORS] = {
 { 0x28, 0xAA, 0x30, 0x41, 0x38, 0x14, 0x01, 0x14 }, // Sensor 1
 { 0x28, 0xAA, 0x24, 0x31, 0x38, 0x14, 0x01, 0xDF }, // Sensor 2
 { 0x28, 0xAA, 0xE4, 0x30, 0x38, 0x14, 0x01, 0x72 }, // Sensor 3
 { 0x28, 0xAA, 0xD4, 0xC2, 0x38, 0x14, 0x01, 0x80 }, // Sensor 4
 { 0x28, 0xAA, 0x6C, 0xDA, 0x38, 0x14, 0x01, 0xD5 }, // Sensor 5
 { 0x28, 0xAA, 0xCA, 0x39, 0x38, 0x14, 0x01, 0xBB }, // Sensor 6
 { 0x28, 0xAA, 0x75, 0x28, 0x38, 0x14, 0x01, 0x2C }, // Sensor 7
 { 0x28, 0xAA, 0xFB, 0xB2, 0x38, 0x14, 0x01, 0xBF }, // Sensor 8
 { 0x28, 0xAA, 0x0F, 0x3A, 0x38, 0x14, 0x01, 0xC3 }, // Sensor 9
 { 0x28, 0xAA, 0x6F, 0x26, 0x38, 0x14, 0x01, 0xF8 }, // Sensor 10
 { 0x28, 0xFF, 0x64, 0x1E, 0x1E, 0x6A, 0x74, 0xF1 }, // Sensor 11
 { 0x28, 0xFF, 0x64, 0x1E, 0x1E, 0x7D, 0x29, 0x55 }, // Sensor 12
 { 0x28, 0xFF, 0x64, 0x1E, 0x1E, 0x73, 0xAC, 0x3A }  // Sensor 13
};

for (int s=0; s<NUMBER_OF_SENSORS; S++) {
  float tempC = sensors.getTempC(SensorAddr[s]);
}