IoT shows Device offline

I had some trouble with OTA-Update. Device was online, but when i tried OTA update there was an error "Board not found". So I decided to delete the device and add it again. The add-process works without error, but the device is always shown as offline in the device-list. The Device shows true at ArduinoCloud.connected();

All other internet-functions like http-post work fine.

Who can help?

@raudaschls which board are you using? Are your properties in synch with the cloud? There is a known issue about the device status that may report the device offline even if connected...

image

but you can doublecheck if the board is connected using a dashboard or looking at the last update column in your thing setup tab

image

Additionaly if the editor shows you the option to do an OTA your device should be correctly connected

image

If you have the board on your desk would be very useful to post the board serial monitor output.

I use Arduino Opta. Since i deleted and added new it shows no activity

Serial shows

15:19:20.195 -> Connected to Arduino IoT Cloud
15:19:20.195 -> Thing ID: 5ed29724-742e-xxxx-a713-7482c74632c6

after Bootup

Now after 2 hours the device is shown as online :man_shrugging:

But OTA-Update still not working:

Careful it looks like you just shared your thing ID.

OTA Update still not working. Is this a known problem?

@raudaschls this forum thread may be related:

you probably need to upload network certificates that are needed in order to perform OTA.

Certificate upload was successful. But still the same error when trying OTA Update.
"Board not found".
image

@raudaschls can you please share the serial monitor output?

There is no output on the serial monitor regarding OTA Update.

That is strange. Are you using ethernet or wifi? Did you try running this sketch

eth - Arduino_Portenta_OTA/examples/OTA_Qspi_Flash_Ethernet/OTA_Qspi_Flash_Ethernet.ino at main · arduino-libraries/Arduino_Portenta_OTA · GitHub

wifi - Arduino_Portenta_OTA/examples/OTA_Qspi_Flash/OTA_Qspi_Flash.ino at main · arduino-libraries/Arduino_Portenta_OTA · GitHub

as suggested in the other forum thread? What is the outcome and the serial monitor output?

I use Ethernet.
Running the eth sketch returns:
image

@raudaschls it looks like also the second qspi partition is corrupted, please run this sketch to reformat the qspi:

Select partition scheme 1 and FatFS.

then reload network certificates with this sketch:

and in the end you should be able to run an OTA with this sketch:

if everything goes well you can retry an OTA from ArduinoIoTCloud

i ran the 3 sketches without errors.
Now i uploaded my sketch via comport and the serial says:

added Device new in the Devicemanager.

Device shown as offline:
image

@raudaschls you need to associate a thing (sketch) to your device

The thing was linked - it was just not on the screenshot. After a few hours the device was suddenly online.
Now i tried ota-update with the same error:
image

No output on the serial monitor regarding ota

Maybe something is slowing down the connection? Can you share your sketch? Are the sketch properties updated correctly from the board?

#include "arduino_secrets.h"
// ArduinoIoTCloud - Version: 1.11.1
#include <ArduinoIoTCloud.h>

// ArduinoHttpClient - Version: Latest 
#include <ArduinoHttpClient.h>

/* 
  Sketch generated by the Arduino IoT Cloud Thing "Untitled 3"
  https://create.arduino.cc/cloud/things/5ed29724-742e-4cbc-a713-7482c74632c6 

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  - No variables have been created, add cloud variables on the Thing Setup page
    to see them declared here

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/
// HttpClient - Version: Latest 

/*
LED_D0: STATUS 1
LED_D1: STATUS 2
LED_D2: STATUS 3
LED_D3: STATUS 4
LED_RESET: LED above the reset button
LED_USER: LED above the user button
*/

#include <b64.h>
// ArduinoRS485 - Version: Latest 
#include <ArduinoRS485.h>
// ArduinoModbus - Version: Latest 
#include <ArduinoModbus.h>
// Ethernet - Version: Latest 
#include <Ethernet.h>
#include <stdlib.h>
#include <stdio.h>
#include <SPI.h>
#include "thingProperties.h"

int i;
int intTemperature, intEnergy;// nur zum Testen
constexpr auto baudrate { 9600 };
// Calculate preDelay and postDelay in microseconds as per Modbus RTU Specification
// MODBUS over serial line specification and implementation guide V1.02
// Paragraph 2.5.1.1 MODBUS Message RTU Framing
// https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf
constexpr auto bitduration { 1.f / baudrate };
constexpr auto preDelayBR { bitduration * 9.6f * 3.5f * 1e6 };
constexpr auto postDelayBR { bitduration * 9.6f * 3.5f * 1e6 };

unsigned long longLastMillis10=0;
unsigned long longLastMillis1=0;
unsigned long longLastMillis5min=0;
unsigned long longLastMillis60min=0;

int intHttpErr=0;
int intConfigSuccess=0;
int intStatusCode=0;
int intHTTPRetry=0;

const int INT_MAX_METER = 25;
const int INT_MAX_IO = 8;

String token="ttttttt";
String password="xxxxxxx";
String strSerial = "H0523A01000001";

struct meter {
  int intMID;
  int intHWtype;
  String strHashCode;
  String strMeterbezeichnung;
  int intValue1;
  int intValue2;
  int intValue3;
  int intValue4;
};
meter allMeter[INT_MAX_METER];
int intCounterInProject = 0;
//meter allMeter[];

struct building {
  String strObjName;
  String strStrasseNr;
  String strPLZ;
  String strOrt;
  int intBID;
};
building thisBuilding;

struct IOChannel{
  int intChNumber;
  String strIOHash;
  int intValue;
};
IOChannel allIOChannel[INT_MAX_IO];
int intIOInProject =0;
//IOChannel allIOChannel[];

struct MeterHW{
  int intMeterType;
  int intNbModbusValuesToRead;
  int intValue1Length; // Anzahl Modbus Register
  int intValue2Length;
  int intValue3Length;
  int intValue4Length;
};

MeterHW MeterHWDef[] = {
  {0,0,0,0,0,0},  //No Hardware 
  {10,1,2,0,0,0}, //Eltako DSZ12DM
  {20,4,2,2,1,1}, //Techem C4s (4 Werte, 2 Register kWh 2 Reg. Volumen, 1 Temp VL 1 RL)
  {30,4,2,2,1,1}, //Techem Ultra S3
  {40,1,2,0,0,0}, //Techem NZR Modularis KWZ Modul
  {50,1,2,0,0,0}, //ABB B23 113-100 - muss noch getestet werden, es könnten auch 3 Modbus Register sein - schauen was das Seneca Teil dazu sagt ###############################
  {60,4,2,2,1,1}, //Salzburg AG UH50
  {70,0,0,0,0,0}  //AutoWMZ - wird hier nicht benötigt
};

bool boolDIcurrentState[INT_MAX_IO];
bool boolDIprevState[INT_MAX_IO];


  // Enter a MAC address for your controller below.
  // Newer Ethernet shields have a MAC address printed on a sticker on the shield
  // The IP address will be dependent on your local network:
byte mac[] = {
    0xA8, 0x61, 0x0A, 0x50, 0x06, 0xA2 //little Hermes02 A8-61-0A-50-06-A2
  };
  //IPAddress ip(192, 168, 1, 200); //enter fixed IP of Opta here

EthernetClient ethClient;
EthernetClient ethClient01;
EthernetClient ethClient02;
HttpClient httpClient(ethClient,"www.sourceburg.at");
HttpClient httpClientIO(ethClient01,"www.sourceburg.at");
HttpClient httpClientHeartBeat(ethClient02,"www.sourceburg.at");

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
  
  RS485.setDelays(preDelayBR, postDelayBR);
  
  if (!ModbusRTUClient.begin(9600)) {
    Serial.println("Failed to start Modbus RTU Client!");
      }
  
  while (Ethernet.begin(mac) != 1)
  {
    Serial.println("Error getting IP address via DHCP, trying again...");
    delay(15000);
  } 
  
  
  //get Config - Anzahl DI, Anzahl/Type Mbus
  intConfigSuccess = F_GetConfig();
  while (intConfigSuccess != 1){
    Serial.println("Error getting config from Hermes-Cloud, trying again...");
    delay(15000);
    intConfigSuccess = F_GetConfig();
  }

  Serial.print("Success getting Config. Zähler: ");
  for(i=0; i<25; i++){
    if (allMeter[i].intHWtype > 0) intCounterInProject +=1;
  }
  Serial.println(intCounterInProject);
  //Serial.print(sizeof(allMeter)/sizeof(allMeter[0]));
  Serial.print("IO Channel: ");
  for(i=0; i<8; i++){
    if (allIOChannel[i].intChNumber > 0) intIOInProject +=1;
  }
  Serial.println(intIOInProject);
  //Serial.println(sizeof(allIOChannel)/sizeof(allIOChannel[0]));
  
  
  // Initialize Opta LEDs
  pinMode(LED_D0, OUTPUT); //---arduino Cloud connected
  pinMode(LED_D1, OUTPUT);
  pinMode(LED_D2, OUTPUT);
  pinMode(LED_D3, OUTPUT);
  // Initialize Relays outputs
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  pinMode(D3, OUTPUT);
  // Initialize DI
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
  pinMode(A4, INPUT);
  pinMode(A5, INPUT);
  pinMode(A6, INPUT);
  pinMode(A7, INPUT);
}

void loop() {
  ArduinoCloud.update();
  
  
  
  //#############################################################################
  //######### Überwachen der Digitaleingänge ####################################
  //######### und Cloud connection           ####################################
  //#############################################################################   
  
  if ((millis()-longLastMillis10)>=5000){
      longLastMillis10=millis();
      
      if (ArduinoCloud.connected()){
        digitalWrite(LED_D0, HIGH);
      }
      else{
        digitalWrite(LED_D0, LOW);
        ArduinoCloud.begin(ArduinoIoTPreferredConnection); // Test ob dann die Verbindung wiederhergestellt wird
      }
      
      
      
      boolDIcurrentState[0] = digitalRead(A0);
      boolDIcurrentState[1] = digitalRead(A1);
      boolDIcurrentState[2] = digitalRead(A2);
      boolDIcurrentState[3] = digitalRead(A3);
      boolDIcurrentState[4] = digitalRead(A4);
      boolDIcurrentState[5] = digitalRead(A5);
      boolDIcurrentState[6] = digitalRead(A6);
      boolDIcurrentState[7] = digitalRead(A7);
      
      
      for (i=0;i<intIOInProject;i++){
        if (boolDIcurrentState[i] != boolDIprevState[i]){
          allIOChannel[i].intValue = boolDIcurrentState[i];
          
          String postData = "her_bid=" + String(thisBuilding.intBID) + "&her_iohash=" + allIOChannel[i].strIOHash + "&her_value=" + String(allIOChannel[i].intValue);
          String strPayload = "";
          intStatusCode=400;
          intHTTPRetry=0;
          
          while (((intStatusCode>299)||(intStatusCode<200)) && (intHTTPRetry<5))
          {
            httpClientIO.beginRequest();
            httpClientIO.post("/hermes/inject_io.php","application/x-www-form-urlencoded",postData);
            httpClientIO.endRequest();
  
            // Ausgabe der Serverantwort
            intStatusCode = httpClientIO.responseStatusCode();
            Serial.print("Status code: ");
            Serial.println(intStatusCode);
            
            if (intHTTPRetry>0) delay(2000);
            intHTTPRetry+=1;
          }
          strPayload = httpClientIO.responseBody();
          httpClientIO.stop();
          
          //strPayload = httpClientIO.responseBody();
          Serial.println("Server response: " + strPayload);
          
        }
      }
      
      for (i=0;i<INT_MAX_IO;i++){
        boolDIprevState[i] = boolDIcurrentState[i];
      }
      
    }
    
    
    /*
    struct IOChannel{
  int intChNumber;
  String strIOHash;
  int intValue;
};
IOChannel allIOChannel[INT_MAX_IO];
int intIOInProject =0;

*/
  //#############################################################################
  //######### Auslesen der Zählerwerte - Modbus Register alle 10s ###############
  //#############################################################################
  
  if ((millis()-longLastMillis1)>=10000){ 
      longLastMillis1=millis();
      
      F_ReadAllMeter();
      for (i=0;i<intCounterInProject;i++){
        Serial.print("Meter: " + String(i+1) + "Value1: ");
        Serial.println(allMeter[i].intValue1);
        Serial.print("Meter: " + String(i+1) + "Value2: ");
        Serial.println(allMeter[i].intValue2);
        Serial.print("Meter: " + String(i+1) + "Value3: ");
        Serial.println(allMeter[i].intValue3);
        Serial.print("Meter: " + String(i+1) + "Value4: ");
        Serial.println(allMeter[i].intValue4);
      }
    }
    
  //#############################################################################
  //######### Schicke Heartbeat alle 5 min ############# ########################
  //#############################################################################
  
  if ((millis()-longLastMillis5min)>=300000){
    longLastMillis5min=millis();
    F_Heartbeat();
  }
  
   //#############################################################################
  //######### Schicke Zählerstände an Hermes Cloud alle 60 min ###################
  //##############################################################################
  
   if ((millis()-longLastMillis60min)>=3600000){ 
    longLastMillis60min=millis();
    F_SendMeterData();
  }
  
  
  // DI Überwachen - bei Änderung push an Hermes Server
  
  
}

void F_SendMeterData(){
  
  for (i=0;i<intCounterInProject;i++){
    String postData="";
    postData = "her_mid=" + String(allMeter[i].intMID) + "&her_hash=" + allMeter[i].strHashCode 
                        + "&her_value=" + String(allMeter[i].intValue1)
                          + "&her_value_add_1=" + String(allMeter[i].intValue2)
                             + "&her_value_add_2=" + String(allMeter[i].intValue3)
                                + "&her_value_add_3=" + String(allMeter[i].intValue4);
     
  
    String strPayload = "";
    httpClient.beginRequest();
    httpClient.post("/hermes/inject.php","application/x-www-form-urlencoded",postData);
    httpClient.endRequest();
    // Ausgabe der Serverantwort
    strPayload = httpClient.responseBody();
    Serial.println("Server response: " + strPayload);
    httpClient.stop();
  }
}




void F_Heartbeat(){
  String postData = "bid=" + String(thisBuilding.intBID) + "&sernum=" + strSerial;
  String strPayload = "";
  
  httpClientHeartBeat.beginRequest();
  httpClientHeartBeat.post("/hermes/heartbeat.php","application/x-www-form-urlencoded",postData);
  httpClientHeartBeat.endRequest();
  
  // Ausgabe der Serverantwort
  strPayload = httpClientHeartBeat.responseBody();
  Serial.println("Server response: " + strPayload);
  httpClientHeartBeat.stop();
  
}

void F_ReadAllMeter(){
  for (i=0;i<intCounterInProject;i++){
    switch (allMeter[i].intHWtype){
      case 0:
        break;
      case 10:
        allMeter[i].intValue1 = F_ReadUINT32 (1,10+i*20);
        break;
      case 20:
        allMeter[i].intValue1 = F_ReadUINT32 (1,10+i*20);
        allMeter[i].intValue2 = F_ReadUINT32 (1,12+i*20);
        allMeter[i].intValue3 = F_ReadUINT16 (1,14+i*20);
        allMeter[i].intValue4 = F_ReadUINT16 (1,16+i*20);
        break;
      case 30:
        allMeter[i].intValue1 = F_ReadUINT32 (1,10+i*20);
        allMeter[i].intValue2 = F_ReadUINT32 (1,12+i*20);
        allMeter[i].intValue3 = F_ReadUINT16 (1,14+i*20);
        allMeter[i].intValue4 = F_ReadUINT16 (1,16+i*20);
        break;
      case 40:
        allMeter[i].intValue1 = F_ReadUINT32 (1,10+i*20);
        break;
      case 50:
        allMeter[i].intValue1 = F_ReadUINT32 (1,10+i*20);
        break;
      case 60:
        allMeter[i].intValue1 = F_ReadUINT32 (1,10+i*20);
        allMeter[i].intValue2 = F_ReadUINT32 (1,12+i*20);
        allMeter[i].intValue3 = F_ReadUINT16 (1,14+i*20);
        allMeter[i].intValue4 = F_ReadUINT16 (1,16+i*20);
        break;
      case 70:
        break;
    }
  }
}



//--------------- Wandelt hex in dec --------------------------
byte F_Hex2Dec (byte byteIN){
  int inthelplow, inthelphigh;
  inthelplow=byteIN & 0x0F;
  inthelphigh=byteIN>>4;
  return inthelplow+inthelphigh*10;
}

//--------------- get Config Function -------------------------

int F_GetConfig(){
  
      String postData = "token=" + token + "&password=" + password;
      String strPayload = "";
      String strLine = "";
      int intPos = 0;
      int intLineType = 0;
      int intCounterCount = -1;
      int intIOCount = -1;
      
      httpClient.beginRequest();
      httpClient.post("/hermes/getconfig.php","application/x-www-form-urlencoded",postData);
      httpClient.endRequest();
      
      // Ausgabe der Serverantwort
      strPayload = httpClient.responseBody();
      Serial.println("Server response: " + strPayload);
      httpClient.stop();

      while (strPayload.indexOf('\r\n', intPos) != -1) {
        strLine = strPayload.substring(intPos, strPayload.indexOf('\r\n', intPos));
        Serial.println("Zeile erhalten: " + strLine);

        // Felder verarbeiten 
        int intFieldPos = 0;
        String strField = "";
        int intFieldCount = 0; // für die weiterverarbeitung in die struct
        
        while (intFieldPos < strLine.length()) {
          int intnextFieldPos = strLine.indexOf(';', intFieldPos);
          if (intnextFieldPos == -1) {
            intnextFieldPos = strLine.length();
          }
          strField = strLine.substring(intFieldPos, intnextFieldPos);
          Serial.println("Feld erhalten: " + strField);
          intFieldPos = intnextFieldPos + 1;
          //Wir checken welches Feld daherkommt 
          //0020 = Gebäude - 5 Nutzfelder
          //0030 = Zähler - 6 Nutzfelder
          //0040 = IO Störmeldung - 4 Nutzfelder
         
          if (strField == "0020"){
            intLineType = 20;
          }
          else if (strField == "0030"){
            intLineType = 30;
            intCounterCount += 1;
          }
          else if (strField == "0040"){
            intLineType = 40;
            intIOCount += 1;
          }
          
          switch (intLineType) {
            case 20:
              // statements
              // Gebäudedaten befüllen
              switch (intFieldCount){
                case 1:
                  thisBuilding.strObjName = strField;
                  break;
                case 2:
                  thisBuilding.strStrasseNr = strField;
                  break;
                case 3:
                  thisBuilding.strPLZ = strField;
                  break;
                case 4:
                  thisBuilding.strOrt = strField;
                  break;
                case 5:
                  thisBuilding.intBID = strField.toInt();
                  break;
              }
              intFieldCount += 1;
              break;
              
            case 30:
              
              switch (intFieldCount){
                case 1:
                  allMeter[intCounterCount].intMID = strField.toInt();
                  break;
                case 2:
                  allMeter[intCounterCount].strHashCode = strField;
                  break;
                case 3:
                  allMeter[intCounterCount].strMeterbezeichnung = strField;
                  break;
                case 5:
                  allMeter[intCounterCount].intHWtype = strField.toInt();
                  break;
                
              }
              intFieldCount += 1;
             
              break;
            case 40:
              // wie legen wir die Störmeldungen an ?? auch struct array
              switch (intFieldCount){
                case 1:
                  allIOChannel[intIOCount].intChNumber = strField.toInt();
                  break;
                case 3:
                  allIOChannel[intIOCount].strIOHash = strField;
                  break;
              }
              intFieldCount += 1;
              
              break;
              
           
          }
        }
        intPos = strPayload.indexOf('\r\n', intPos) + 1;
        
      }
  return 1;
}

    //####################################################################################################
    //########## Funktion liest einen Uint32 Wert via Modbus         ########################################
    //####################################################################################################

  unsigned int F_ReadUINT32 (int intSlaveID, int intStartReg){

  unsigned int i, uintReadValue;
  word wordtemp=0;
  byte bytetemp=0;
  
    //--------- read --------------
    if (!ModbusRTUClient.requestFrom(intSlaveID, HOLDING_REGISTERS, intStartReg, 2)) {
    Serial.print("failed to read registers! ");
    Serial.println(ModbusRTUClient.lastError());
    } 
    else {
      
        wordtemp=ModbusRTUClient.read();
        bytetemp=wordtemp;
        uintReadValue=F_Hex2Dec(bytetemp)*10000;
        bytetemp=wordtemp>>8;
        uintReadValue+=F_Hex2Dec(bytetemp)*1000000;
        wordtemp=0;
        bytetemp=0;
        wordtemp=ModbusRTUClient.read();
        bytetemp=wordtemp;
        uintReadValue+=F_Hex2Dec(bytetemp);
        bytetemp=wordtemp>>8;
        uintReadValue+=F_Hex2Dec(bytetemp)*100;
    }
  return uintReadValue;
}


int F_ReadUINT16 (int intSlaveID, int intStartReg){
  word wordtemp=0;
  byte bytetemp=0;
  int i, intReadValue;
    if (!ModbusRTUClient.requestFrom(intSlaveID, HOLDING_REGISTERS, intStartReg, 1)) {
    Serial.print("failed to read registers! ");
    Serial.println(ModbusRTUClient.lastError());
    } 
    else {
      
        wordtemp=ModbusRTUClient.read();
        bytetemp=wordtemp;
        intReadValue=F_Hex2Dec(bytetemp);
        bytetemp=wordtemp>>8;
        intReadValue+=F_Hex2Dec(bytetemp)*100;
      
    }
  return intReadValue;
}




This can be an issue / edge case, I seem to recall that OTA is not working if you don't have at least one property declared. Can you please try to add at least one propetry to your sketch?

I think it would be also a good idea try with a basic sketch so we can easily identify the issue.