Парсинг строки порта

Вот тебе минимальный пример. По аналогии сам сообразишь.
Если ты принимаешь параметр в кавычках - то это строка, и попытка прочитать его как число вернет НОЛЬ. Поэтому тебя про кавычки и спрашивал ИксДрайвер вначале.

#include <ArduinoJson.h>

struct Data {
  float temp;
  char name[20];
  int count;
};

String input;

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

  Serial.println("Enter JSON and press Enter:");
  Serial.println("{\"temp\":23.5,\"name\":\"sensor1\",\"count\":7}");
}

void loop() {
  // читаем строку до перевода строки
  if (Serial.available()) {
    input = Serial.readStringUntil('\n');

    // убираем возможный \r
    input.trim();

    if (input.length() == 0) return;

    StaticJsonDocument<128> doc;
    DeserializationError err = deserializeJson(doc, input);

    if (err) {
      Serial.print("Parse error: ");
      Serial.println(err.c_str());
      return;
    }

    Data data;

    data.temp  = doc["temp"];
    data.count = doc["count"];
    strlcpy(data.name, doc["name"] | "", sizeof(data.name));

    Serial.println("OK:");
    Serial.print("temp = "); Serial.println(data.temp);
    Serial.print("name = "); Serial.println(data.name);
    Serial.print("count = "); Serial.println(data.count);

    Serial.println("\nEnter next JSON:");
  }
}

Еще раз, зачем нужно всякое говно, если есть просто стандартная?
ПРимер посмотри, я выше написал

Я уже выше писал одному любителю “все сам”… что можно самому в сортире делать, но с подругой или женой - гораздо комфортнее.
Так и строки JSON парсить самому - тоже вариант рукоблудия. Некоторым - нравится. :wink: В принципе свобода выбора есть всегда.

Злые вы все. Нет, чтобы человеку посоветовать что-нить типа такого

он б изучил много полезного и интересного :slight_smile:

сразу видно лентяй, не думали заранее как их потом парсить))) я бы переписал то что отправляет наверное…

прошивку датчика делал не я но исходник есть , а что не так то и как правильнее было бы могу и переделать ?

да действительно json библиотека оказалось наилучшем решением , быстро разобрался как с ней работать ,всем спасибо за подсказку.

у меня еще вопрос на моей плате остались неиспользованные пины Esp32 gpio 11 12 13 19 я могу их использовать как UART ?

счас для пробы подсоединил HC12 на 17 18 pin Serial1.begin(9600, SERIAL_8N1, 17, 18); работает но они у меня заняты под I2C.

если можете вот парсер, под float наверное тоже сможете переделать… легко отправляете и парсите…


код для платы 1:

void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("R1G2B3");
Serial.println(' ');
delay(1000);
Serial.println("R4G5B6");
Serial.println(' ');
delay(1000);
Serial.println("R7G8B9");
Serial.println(' ');
delay(1000);
Serial.println("R10G11B12");
Serial.println(' ');
delay(1000);
Serial.println("R13G14B15");
Serial.println(' ');
delay(1000);
}

код для платы 2:

int a = 0;
int b = 0;
int c = 0;

void setup() {
Serial.begin(115200); // Инициализация последовательного порта на скорости 115200 бод
}

void loop() {
if (Serial.available() > 0) { // Проверяем, есть ли доступные данные
String input = Serial.readStringUntil('\n'); // Читаем строку до символа новой строки
// Проверяем, начинается ли строка с 'R' и содержит 'G' и 'B'
if (input.startsWith("R") && input.indexOf('G') > 1 && input.indexOf('B') > 1) {
// Извлекаем значения
int rIndex = input.indexOf('R') + 1;
int gIndex = input.indexOf('G');
int bIndex = input.indexOf('B');
// Извлекаем числа из строки
a = input.substring(rIndex, gIndex).toInt();
b = input.substring(gIndex + 1, bIndex).toInt();
c = input.substring(bIndex + 1).toInt();

Serial.print(a);
Serial.print(' ');
Serial.print(b);
Serial.print(' ');
Serial.print(c);
Serial.print(' ');
}
}
}//конец

Все у тебя норм, не слушай чушь собачью. 100500 лет назад, когда контроллеры были с 1 или 2 килобайтами памяти, люди писали форматы сообщений так, чтобы их было удобно читать слабенькими железками.
В 21 веке эту практику можно забыть, как страшный сон, если ты не проектируешь обмен сообщениями с Марсом или космической станцией на орбите спутника Юпитера ;).
JSON - вот самое то, что надо. И человек это удобно читает или пишет и компьютеру не трудно.
Кроме того, вот прямо с этом же JSON можно все это скидывать на MQTT сервер в сети, и писать мониторинг, который смотреть в браузере.

Если с учетом того, что кавычек у первого параметра нет, то так:

#include <stdio.h>
#include <stdint.h>

struct wSensorData {

    uint16_t bat;      // вольтаж
    uint8_t  num;      // номер
    int16_t  temp;     // температура * 100
    uint8_t  hum;      // влажность
    uint16_t press;    // давление
    char     type[16]; // тип. тут была ошибка.
};



// Распарсивает строчку вида
// {“b”:410,“num”:“0”,“t”:26.37,“h”:27.54,“p”:988.48,“s”:“BME280”} в структуру.
// Хначение первого элемента (b) дано без кавычек. Если нужны кавычки, то нужно исправить аргумент sscanf() ниже

int parse_sensor_reply(const char *a, struct wSensorData *out) {

    float t, h, p;
    unsigned num;

    // Да, sscanf(). А вы думали тут парсер хитрый увидеть? :)
    int rc = sscanf(a,
        "{\"b\":%hu,\"num\":\"%u\",\"t\":%f,\"h\":%f,\"p\":%f,\"s\":\"%15[^\"]\"}",
        &out->bat,
        &num,
        &t,
        &h,
        &p,
        out->type);

    if (rc != 6) {
        printf(":-( %d\r\n",rc);
        return -1;
    }

    out->num   = (uint8_t)num;
    out->temp  = (int16_t)(t * 100.0f);   // 26.37 -> 2637
    out->hum   = (uint8_t)(h + 0.5f);     // округление
    out->press = (uint16_t)(p + 0.5f);

    return 0;
}




// Пример использования.

int main() {

  // Куда сохранять данные
  struct wSensorData out;

  // Строчка-ответ от сенсора. Пример из топика
  const char *str = "{\"b\":410,\"num\":\"0\",\"t\":26.37,\"h\":27.54,\"p\":988.48,\"s\":\"BME280\"}";

  // вся магия тут
  if (parse_sensor_reply(str, &out) < 0)
    printf("Строчка непонятная\r\n");
  else {

    // Печатаем строчку исходную
    printf("Sensor_Reply=[%s]\r\n", str);


    // Печатаем наобум какой-нибудь параметр, температуру, например. Проверить , чтобы
    printf("Temperature: %d.%02d C\r\n", out.temp / 100, out.temp % 100);
  }

  return 0;


}

Как правильно - выше сказали, но на моё ИМХО, начинающему можно и “в рукопашную” на первых порах повозиться
Примерно так, в общих чертах(весь код лень писать…)))

Спойлер

char * inData = "{“b”:410,“num”:“0”,“t”:26.37,“h”:27.54,“p”:988.48,“s”:“BME280”}";

struct wSensorData {
  uint16_t bat;    //вольтаж
  uint8_t num;     //номер
  int16_t temp;    //температура
  uint8_t hum;     //влажность
  uint16_t press;  //давление
  char * type;       //тип
};

struct wSensorData readData(char * inCh)
{

  struct wSensorData wSens = {0};

  uint8_t ind = 0;
  char ch;

  if ((ch = *(inCh + ind++)) == '{')
  {
    while (ch = *(inCh + ind++))
    {
      switch (ch)
      {
        case 'b':
          uint8_t mul = 100;//вес старшего разряда
          while ((ch = *(inCh + ind++)) != ':'); //пропускаем до ':'
          while ((ch = *(inCh + ind++)) != ',')// считаем число до запятой
          {
            wSens.bat += (ch - 48) * mul;
            mul /= 10;
          }        
          break;
        case 'n'://дальше по такому же принципу
          break;
        case 't':
          break;
        case 'h':
          break;
        case 'p':
          break;
        case 's':
          break;
      }
    }
  }
  return wSens;
}

void setup() {
  Serial.begin(115200);
  Serial.println(readData(inData).bat);
}

void loop() {}

Спойлер

Screenshot_398 - копия

Уточните, у вас есть возможность перекомпилировать код, который со стороны датчика посылает данные?

да могу , взял его за основу тк он rf433 HC12 и мне важна дальность

вот код где формируется пакет


#include <Adafruit_Sensor.h> // v1.1.3 https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_BME280.h> // v2.0.2 https://github.com/adafruit/Adafruit_BME280_Library
#include "SHT21.h"           // v1.0.0 https://github.com/markbeee/SHT21
#include <microDS18B20.h>    // v3.5.0 https://github.com/GyverLibs/microDS18B20
#include <MAX44009.h>        // v1.2.3 https://github.com/dantudose/MAX44009
#include <BH1750.h>          // v1.1.4 https://github.com/claws/BH1750
#include <PZEM004Tv30.h>     // v1.1.2 https://github.com/mandulaj/PZEM-004T-v30
#include <s8_uart.h>         // v1.0.1 https://github.com/jcomas/S8_UART

#include <SoftwareSerial.h>
#include "config.h"
#include "BIM32_Radio-sensor.h"
#include "tm1637.h"

Adafruit_BME280 bme280;
SHT21 SHT21;
MicroDS18B20<ONE_WIRE_1> ds18b20_1;
MicroDS18B20<ONE_WIRE_2> ds18b20_2;
MicroDS18B20<ONE_WIRE_3> ds18b20_3;
MicroDS18B20<ONE_WIRE_4> ds18b20_4;
MAX44009 max44009;
BH1750 bh1750(0x23);
SoftwareSerial pzemSWSerial(PZEM_RX, PZEM_TX);
PZEM004Tv30 pzem(pzemSWSerial);
SoftwareSerial S8_serial(SENSEAIR_RX, SENSEAIR_TX);
S8_UART *sensor_S8;
S8_sensor sensor; 
TM1637 tm1637;

inline static int getBatteryVoltage(const int internalRefference = 11000) {
  ADCSRA = (bit(ADPS2) | bit(ADPS1) | bit(ADPS0));
  ADCSRA |= bit(ADEN);
  ADMUX = 0;
  ADCSRB = 0;
  ADMUX = (ADMUX & 0x2F) | 0x40;
  ADMUX &= ~bit(ADLAR);
  ADMUX = (ADMUX & 0xF0) | 14;
  delay(1); // пусть "пропитается"
  for (ADCSRA |= bit(ADSC); ADCSRA & bit(ADSC);); // Первый замер ни о чём
  for (ADCSRA |= bit(ADSC); ADCSRA & bit(ADSC);); // Замеряем
  while (ADCSRA & bit(ADSC));
  const int adc = ADC;
  return (((internalRefference * 1024L + adc / 2) / adc) + 500) / 1000;
}

void setup() {
  // Initialization pins to output
  uint8_t pins[] = {12, 13, A0, A1, A3, SET, DONE};
  for(uint8_t i=0; i<sizeof(pins); i++) pinMode(pins[i], OUTPUT);
  
  // Determining the logical state of pins
  digitalWrite(DONE, LOW);
  digitalWrite(SET, HIGH);
  
  // ADC reference voltage setting
  analogReference(INTERNAL);

  // Start serial interface
  Serial.begin(9600);
  while(!Serial);
  
  // Start each software serial port
  pzemSWSerial.begin(9600);
  S8_serial.begin(S8_BAUDRATE);
  sensor_S8 = new S8_UART(S8_serial);
  
  // Sensors initialization
  sensorsInit();
  // Data send
  dataSend();
  delay(30); 
  // Power off
//  Serial.print(getBatteryVoltage(11000)); // внутреннее опорное напряжение 1,0522В
//  delay(100);
  powerOff();
}

void loop() {
  tm1637.print(datas.temp_1); /* Displaying sensor data on display TM1637 */
  
  /* 
   * If the power does not turn off, send data and try to 
   * turn off the power again every 5 seconds
   */
  delay(5000);
  dataSend();
  powerOff();

  if(detected.ds18b20_1) ds18b20_1.requestTemp();
  if(detected.ds18b20_2) ds18b20_2.requestTemp();
  if(detected.ds18b20_3) ds18b20_3.requestTemp();
  if(detected.ds18b20_4) ds18b20_4.requestTemp();
}


/**
 * Power off
 */
void powerOff(void) {
  digitalWrite(DONE, HIGH);
  delay(5);
  digitalWrite(DONE, LOW);
  delay(5);
  digitalWrite(DONE, HIGH);
  delay(10);
}

/**
 * Send data via UART
 */
void dataSend(void) {
  getData();
  uint8_t attempts = 0;

  // wait if another wireless sensor is transmitting data now, 
  // but no more than 5 seconds
  while(Serial.available()) {
    if(attempts++ > 25) break;
    Serial.read();
    delay(200);
  }
  
  // send data
  Serial.print("{");
  Serial.print("\"b\":"); Serial.print(datas.adc);
 // Serial.print("\"b\":"); Serial.print(getBatteryVoltage(11000));
  Serial.print(",\"num\":\""); Serial.print(SENSOR_NUMBER); Serial.print("\"");
  if(detected.bme280) {
    Serial.print(",\"t\":"); Serial.print(datas.temp);
    Serial.print(",\"h\":"); Serial.print(datas.hum);
    Serial.print(",\"p\":"); Serial.print(datas.pres);
    Serial.print(",\"s\":"); Serial.print("\"BME280\"");
  }
  else if(detected.sht21) {
    Serial.print(",\"t\":"); Serial.print(datas.temp);
    Serial.print(",\"h\":"); Serial.print(datas.hum);
    Serial.print(",\"s\":"); Serial.print("\"SHT21\"");
  }
  if(detected.max44009) {
    Serial.print(",\"l\":"); Serial.print(datas.light);
    Serial.print(",\"a\":"); Serial.print("\"MAX44009\"");
  }
  else if(detected.bh1750) {
    Serial.print(",\"l\":"); Serial.print(datas.light);
    Serial.print(",\"a\":"); Serial.print("\"BH1750\"");
  }
  #ifdef USE_DS18B20_1
    Serial.print(",\"ds\":["); Serial.print(datas.temp_1); 
    Serial.print(","); Serial.print(datas.temp_2);
    Serial.print(","); Serial.print(datas.temp_3);
    Serial.print(","); Serial.print(datas.temp_4);
    Serial.print("]");
  #endif
  #ifdef USE_PZEM_004T
    Serial.print(",\"pzem\":[");
    Serial.print(datas.voltage, 1); Serial.print(",");
    Serial.print(datas.current, 3); Serial.print(",");
    Serial.print(datas.power, 1); Serial.print(",");
    Serial.print(datas.energy, 2); Serial.print(",");
    Serial.print(datas.frequency, 1); Serial.print(",");
    Serial.print(datas.pf, 2);
    Serial.print("]");
  #endif
  if(detected.s8) {
    Serial.print(",\"s8\":"); Serial.print(datas.co2);
  }
  Serial.println("}");
  Serial.flush();
  #ifdef USE_DS18B20_1
    delay(50);
  #endif
}

Перепишите код отправки так, чтобы вам было удобно его парсить. А вообще правильно в бинарном виде передавать, если у вас нет потребности наблюдать его в терминале. Или в читаемом виде как текст передавайте только в отладочном режиме, а когда устройства сопряжены, то обмениваются по бинарному протоколу.

И проверку CRC добавить

И повторные отправки и нумераторы посылок тоже добавь, вдруг один модуль отправит, а другой не услушит.
И далее ты дойдешь до этапа, что нужно передавать не только основные данные, но и еще в 10 раз больше служебных… Серийный номер датчика, дата, время, срок актуальности данных, гпс координаты, версия протокола передачи, название оправителя, контрольная сумма, сертификат безопасности и т.д. :grinning_face:

Забыли про дату последней поверки датчика и дату следующей. Чтобы прибор можно было настроить “предупреди за Х дней, чтобы не забыть о поверке”.

да все и так отлично работает ни одного пакета вроде не потеряно и это с учетом большого расстояния.

счас доработаю программу датчика расчет питания напрямую а то хрень какую то показывает , Евгений поделился исходником.

Красивое однако, но увы меня не впечетляет.

я только начал проект будет лучше )

У меня кот метеостаниция.
Если пришел мокрый - идет дождь.
Если пришел грязный и мокрый - идет дождь.
Если пришел грязный и сухой - дождь занончился.
Если пришол холодный - на улице холодно.
Если сидит дома и смотрит в окно - на улице очень холодно.
Если не дома - метеостация не готова предоставить данные, ожидайте ответа.