Example #1
0
bool OwRelay::rawWrite(uint64_t addr, bool value) {
  OneWire ds = os->getOneWire();
  uint8_t *a = (uint8_t *)&addr;
  ds.reset();
  ds.write(0x55, 1); // ROM select
  for(int i = 0; i < 8; i++) ds.write(a[i], 1);
  uint8_t bit = ds.read_bit();
  ds.reset();

  bool oops = false;
  value ^= 1;
  if ((bit&1) ^ value) {
    oops = true;
    // toggled the wrong way, toggle again...
    ds.write(0x55, 1); // ROM select
    for(int i = 0; i < 8; i++) ds.write(a[i], 1);
    bit = ds.read_bit();
    ds.reset();
  }
#if DEBUG
  Serial.print(F("OWR: Write "));
  printAddr(&Serial, addr);
  Serial.print("<-");
  Serial.print(value);
  if (oops) Serial.print(" 2xtoggle");
  Serial.print(" bit=");
  Serial.print(bit);
  Serial.println();
#endif

  return !((bit&1) ^ value);
}
Example #2
0
float getTemp(OneWire ds){
  //returns the temperature from one DS18S20 in DEG Celsius
  unsigned long currentMillis = millis();
  static long previousMillis = 0;  

  if(currentMillis - previousMillis > TempSampleInterval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;


    byte data[12];
    byte addr[8];

    if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
    }

    if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
    }

    if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
    }

    ds.reset();
    ds.select(addr);
    ds.write(0x44,1); // start conversion, with parasite power on at the end

    byte present = ds.reset();
    ds.select(addr);    
    ds.write(0xBE); // Read Scratchpad


    for (int i = 0; i < 9; i++) { // we need 9 bytes
      data[i] = ds.read();
    }

    ds.reset_search();

    byte MSB = data[1];
    byte LSB = data[0];

    float tempRead = ((MSB << 8) | LSB); //using two's compliment
    float TemperatureSum = tempRead / 16;


//    Serial.print("Temperature:   ");
//    Serial.print(TemperatureSum);
//    Serial.print('\n');
    
    return TemperatureSum;

  }
}
Example #3
0
void loop(void) {
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];
  
  if ( !ds.search(addr)) {
    Serial.print("No more addresses.\n");
    ds.reset_search();
    delay(1250);
    return;
  }
  
  Serial.print("R=");
  for( i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.print("CRC is not valid!\n");
      return;
  }
  
  if ( addr[0] != 0x28) {
      Serial.print("Device is not a DS18B20 family device.\n");
      return;
  }

  // The DallasTemperature library can do all this work for you!

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end
  
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("P=");
  Serial.print(present,HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print( OneWire::crc8( data, 8), HEX);
  Serial.println();
}
Example #4
0
// Read the state, returns -1 on failure
int8_t OwRelay::rawRead(uint64_t addr) {
  OneWire ds = os->getOneWire();
  byte data[12];
  ds.reset();
  ds.select((uint8_t *)&addr);
  uint8_t value = ds.read_bit() ^ 1; // read the switch value

#if DEBUG
  Serial.print(F("OWR: Good data for "));
  printAddr(&Serial, addr);
  Serial.print("->");
  Serial.print(value);
  Serial.println();
#endif

  return value;
}
 ///<summary> Retrieve the temperature from the OneWire sensor</summary>
 ///<param name="Sensors">Location of the bus for the OneWire sensors</param>
 ///<return>True if successful, false otherwise</return>
 bool TemperatureSensor::RetrieveTemperatureFromSensor(OneWire Sensors)
 {
     float retVal = INVALID_DATA;
     byte data[2];
   //Found the sensor we were looking for, read the data from it
     if(0 == Sensors.reset())
     {
       Logger::Log(F("Unable to reset the bus"), ERR);
       goto cleanup;
     }  
     
     Sensors.select(m_SensorAddress);
     
     //Send the 0x44 command, which is the convert command
     Sensors.write(0x44);

	 //TODO: Can only do this when not in parasitic power mode
	 while(Sensors.read() == 0) 
	 {
		 //Chill for 5 ms to see if it's all done
		 delay(5);
	 }

	 //TODO: This might not be needed for non-parasite powered sensors
     if(0 == Sensors.reset())
     {
       Logger::Log(F("Unable to reset the bus after converting temperature"), ERR);
       goto cleanup;
     }
     Sensors.select(m_SensorAddress);
	 
	 

     //Send the 0xBE command, which is read the scratchpad
     Sensors.write(0xBE);     
     
     //The data is of the format LSB, MSB
     data[0] = Sensors.read();
     data[1] = Sensors.read();
     retVal = ((data[1] << 8) | data[0]); //using two's compliment
     retVal = retVal / 16.0;
     retVal = Utility::ToFahrenheit(retVal);
     
     //Reset the communication
     Sensors.reset();
     
     //Assign our temperature data
     m_Temperature = retVal;
cleanup:     
     return retVal;
 }
Example #6
0
float Temperature::getTemp(OneWire ds){

	 if ( !ds.search(_addr)) {
	   //no more sensors on chain, reset search
	   ds.reset_search();
	   return -1000;
	 }

	 if ( OneWire::crc8( _addr, 7) != _addr[7]) {
	   Serial.println("CRC is not valid!");
	   return -1000;
	 }

	 if ( _addr[0] != 0x10 && _addr[0] != 0x28) {
	   Serial.print("Device is not recognized");
	   return -1000;
	 }

	 ds.reset();
	 ds.select(_addr);
	 ds.write(0x44,1); // start conversion, with parasite power on at the end

	 _present = ds.reset();
	 ds.select(_addr);  
	 ds.write(0xBE); // Read Scratchpad

 
	 for (int i = 0; i < 9; i++) { // we need 9 bytes
	  _data[i] = ds.read();
	 }
 
	 ds.reset_search();
 
	 _MSB = _data[1];
	 _LSB = _data[0];

	 _tempRead = ((_MSB << 8) | _LSB); //using two's compliment
	 _TemperatureSum = _tempRead / 16;
 
	 return _TemperatureSum;
}
Example #7
0
/**
 * Set the temperature resolution. While this speeds up conversion, it also
 * reduces accuracy.
 *
 * @param ds OneWire instance configured for communication with the DS18B20.
 * @param res One of the resolution constants to set the appropriate resolution.
 * @return Success or failure
 */
bool DS18B20::setResolution(OneWire ds, byte res) {
    byte addr[8];           // address buffer
    int deviceCount = 0;    // track number of devices serviced

    // Make sure the resolution byte sent in is valid.
    if (res != RES_9BIT && res != RES_10BIT && res != RES_11BIT && res != RES_12BIT)
        return false;

    // Do this while devices are available
    ds.reset_search();
    while (ds.search(addr)) {
        // Count this device
        deviceCount++;

        // Verify the CRC of the address
        if ( OneWire::crc8( addr, 7) != addr[7]) {
            return false;
        }

        // Verify the device is recognized by looking at the device ID in the
        // first byte of the address (=0x28).
        if (addr[0] != DS18B20_CODE) {
            return false;
        }

        // Write to the scratchpad register. See pg. 11 of datasheet. This
        // requires sending the write command and then 3 bytes. The first two
        // set alarms...these are not used. The third is the resolution.
        ds.reset();
        ds.select(addr);
        ds.write(CMD_WRITE_SPAD); // 0x4E = write scratchpad
        ds.write(ALARM_DISABLED); // alarm low setting = 0 (not used)
        ds.write(ALARM_DISABLED); // alarm high setting = 0 (not used)
        ds.write(res);            // resolution
    }

    // If we didn't catch any devices, return false
    if (deviceCount == 0)
        return false;
    // If we did, return true
    else
        return true;
}
Example #8
0
void setup() {
  memset(voltsChr,0,sizeof(voltsChr));
  memset(amps0Chr,0,sizeof(amps0Chr));
  memset(amps1Chr,0,sizeof(amps1Chr));
  memset(tmpChr,0,sizeof(tmpChr));

    // if the program crashed, skip things that might make it crash
  String rebootMsg = ESP.getResetReason();
  if (rebootMsg=="Exception") safeMode=true;
  else if (rebootMsg=="Hardware Watchdog") safeMode=true;
  else if (rebootMsg=="Unknown") safeMode=true;
  else if (rebootMsg=="Software Watchdog") safeMode=true;

  if (sw1>=0) {
    pinMode(sw1, OUTPUT);
  }
  if (sw2>=0) {
    pinMode(sw2, OUTPUT);
  }
  if (sw3>=0) {
    pinMode(sw3, OUTPUT);
  }
  if (sw4>=0) {
    pinMode(sw4, OUTPUT);
  }

  // "mount" the filesystem
  bool success = SPIFFS.begin();
  if (!success) SPIFFS.format();

  if (!safeMode) fsConfig(); // read node config from FS

#ifdef _TRAILER
  wifiMulti.addAP("DXtrailer", "2317239216");
#else
  wifiMulti.addAP("Tell my WiFi I love her", "2317239216");
#endif

  int wifiConnect = 240;
  while ((wifiMulti.run() != WL_CONNECTED) && (wifiConnect-- > 0)) { // spend 2 minutes trying to connect to wifi
    // connecting to wifi
    delay(1000);
  }

  if (wifiMulti.run() != WL_CONNECTED ) { // still not connected? reboot!
    ESP.reset();
    delay(5000);
  }

  if (hasHostname) { // valid config found on FS, set network name
    WiFi.hostname(String(nodename)); // set network hostname
    ArduinoOTA.setHostname(nodename);  // OTA hostname defaults to esp8266-[ChipID]
    MDNS.begin(nodename); // set mDNS hostname
  }

  WiFi.macAddress(mac); // get esp mac address, store it in memory, build fw update url
  sprintf(macStr,"%x%x%x%x%x%x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  sprintf(theURL,"/iotfw?mac=%s", macStr);

  // request latest config from web api
  if (!safeMode) getConfig();

  // check web api for new firmware
  if (!safeMode) httpUpdater();

  // start UDP for ntp client
  udp.begin(localPort);

  updateNTP();

  setSyncProvider(getNtptime); // use NTP to get current time
  setSyncInterval(600); // refresh clock every 10 min

#ifndef _MINI
  // start the webserver
  httpd.onNotFound(handleNotFound);
  httpd.begin();
  // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 80);
#endif

  // start websockets server
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);

  // setup other things
  setupOTA();
  setupMQTT();

  // setup i2c if configured, basic sanity checking on configuration
  if (hasI2C && iotSDA>=0 && iotSCL>=0 && iotSDA!=iotSCL) {
    sprintf(str,"I2C enabled, using SDA=%u SCL=%u", iotSDA, iotSCL);
    mqtt.publish(mqttpub, str);

    Wire.begin(iotSDA, iotSCL); // from api config file

    //Wire.begin(12, 14); // from api config file
    i2c_scan();

    printConfig();

    if (hasRGB) setupRGB();
    if (hasIout) setupADS();
    if (hasSpeed) setupSpeed();

  }

  // OWDAT = 4;
  if (OWDAT>0) { // setup onewire if data line is using pin 1 or greater
    sprintf(str,"Onewire Data OWDAT=%u", OWDAT);
    mqtt.publish(mqttpub, str);
    oneWire.begin(OWDAT);
    if (hasTout) {
      ds18b20 = DallasTemperature(&oneWire);
      ds18b20.begin(); // start one wire temp probe
    }
    if (hasTpwr>0) {
      pinMode(hasTpwr, OUTPUT); // onewire power pin as output
      digitalWrite(hasTpwr, LOW); // ow off
    }
  }


  if (useMQTT) {
    String rebootReason = String("Last reboot cause was ") + rebootMsg;
    rebootReason.toCharArray(str, rebootReason.length()+1);
    mqtt.publish(mqttpub, str);
  }
}
void ReadTemp(Temp& reading) {
    byte i;
    byte present = 0;
    byte type_s;
    byte data[12];

    if ( !ds.search(reading.addr)) {
        ds.reset_search();
        delay(250);
        return;
    }

    if (OneWire::crc8(reading.addr, 7) != reading.addr[7]) {
        Serial.println("CRC is not valid!");
        return;
    }

    // the first ROM byte indicates which chip
    switch (reading.addr[0]) {
    case 0x10:
        type_s = 1;
        break;
    case 0x28:
        type_s = 0;
        break;
    case 0x22:
        type_s = 0;
        break;
    default:
        Serial.println("Device is not a DS18x20 family device.");
        return;
    }

    ds.reset();
    ds.select(reading.addr);
    ds.write(0x44, 1);        // start conversion, with parasite power on at the end

    delay(750);     // maybe 750ms is enough, maybe not
    // we might do a ds.depower() here, but the reset will take care of it.

    present = ds.reset();
    ds.select(reading.addr);
    ds.write(0xBE);         // Read Scratchpad

    for ( i = 0; i < 9; i++) {           // we need 9 bytes
        data[i] = ds.read();
    }

    // Convert the data to actual temperature
    // because the result is a 16 bit signed integer, it should
    // be stored to an "int16_t" type, which is always 16 bits
    // even when compiled on a 32 bit processor.
    int16_t raw = (data[1] << 8) | data[0];
    if (type_s) {
        raw = raw << 3; // 9 bit resolution default
        if (data[7] == 0x10) {
            // "count remain" gives full 12 bit resolution
            raw = (raw & 0xFFF0) + 12 - data[6];
        }
    } else {
        byte cfg = (data[4] & 0x60);
        // at lower res, the low bits are undefined, so let's zero them
        if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
        else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
        else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
        //// default is 12 bit resolution, 750 ms conversion time
    }
    reading.celsius = (raw / 16.0) * 100;
    reading.didRead = true;
}
void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }

  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();

  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      return;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end

  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  present = ds.reset();
  ds.select(addr);
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("  Data = ");
  Serial.print(present, HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print(OneWire::crc8(data, 8), HEX);
  Serial.println();

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
}
///<summary>Go through the collection of sensors and validate that we have the
///requested sensor on the system.</summary>
///<param name="Sensors"> The OneWire bus that contains the temperature sensors</param>
///<return> True if found, false otherwise</return>
 bool TemperatureSensor::DoesSensorExist(OneWire Sensors)
 {
   bool retVal = false;
   byte foundSensorAddress[8];

   Logger::PrependLogStatement(DEB);
   Logger::LogStatement(F("Searching for "), DEB);   
   Logger::LogStatement(m_SensorAddress, DEB);
   Logger::EndLogStatement(DEB);

   while(true == Sensors.search(foundSensorAddress))
   {
     bool found = true;   
     

     //Print out the data
	 Logger::PrependLogStatement(DEB);
     Logger::LogStatement(F("Found sensor "), DEB);   
	 Logger::LogStatement(foundSensorAddress, DEB);
	 Logger::EndLogStatement(DEB);        


     //See if this is a valid address
     if ( OneWire::crc8( foundSensorAddress, 7) != foundSensorAddress[7]) {
          Logger::Log(F("CRC is not valid!"), WAR);
          Sensors.reset();
          Sensors.reset_search();
          break;
      }     
      if ( foundSensorAddress[0] != 0x10 && foundSensorAddress[0] != 0x28) {
        Logger::Log(F("Device is not recognized"), WAR);
        continue;
      }
      
     //We found a valid device on the wire.  See if it's a match
     for(int i = 0; i < 8; i++)
     {
       if(m_SensorAddress[i] != foundSensorAddress[i])
       {
         found = false;
         break;
       }
     }
     //See if we found a match
     if(true == found)
     {
       //This is the sensor we're looking for
       Logger::Log(F("Found sensor"), DEB);
       retVal = true;
       break;      
     }     
   }  

   Logger::Log(F("Done searching for sensors"), DEB);


   
cleanup:
  //Reset the temperature sensor search for subsequent invocations
  Sensors.reset_search();
  return retVal;   
 }
Example #12
0
/**
 * Get a float representing the temperature from the DS18B20.
 *
 * @param ds OneWire instance configured for communication with the DS18B20.
 * @return The average temperature in Fahrenheit of all devices, or 0 if fail.
 */
float DS18B20::getTemperature(OneWire ds) {
    byte data[12];  // data buffer
    byte addr[8];   // address buffer
    byte deviceCount = 0;   // number of devices taken care of
    float avgTemp = 0.0;    // the average temperature to be returned

    // Search for a new device on the bus. If 1, a new device is available. If 0,
    // the bus may be in error, nothing may be connected, or all devices have been
    // read. This should allow for multiple sensors on the same bus (must remove
    // else block). The address of the next device will be stored in addr.
    ds.reset_search();
    while (ds.search(addr)) {
        // Count this device
        deviceCount++;

        // Verify the CRC of the address
        if ( OneWire::crc8( addr, 7) != addr[7]) {
            //Serial.println("CRC is not valid!");
            return 0.0;
        }

        // Verify the device is recognized by looking at the device ID in the
        // first byte of the address (=0x28).
        if (addr[0] != DS18B20_CODE) {
            //Serial.println("Device not recognized!");
            return 0.0;
        }

        // Begin a temperature conversion
        ds.reset();
        ds.select(addr);
        ds.write(CMD_CONVERT_TEMP);   // 0x44 = start conversion

        // Hard delay to get the most up-to-date reading. This gives the most time accurate reading
        // but locks the processor up from doing anything else. The existing method where we read
        // the *previous* reading every 1 second is suitable and increases utilization.
        //delay(1000);

        // Request to read the temperature sensor's scratchpad for the converted temperature
        ds.reset();
        ds.select(addr);
        ds.write(CMD_READ_SPAD);   // 0xBE = read scratchpad

        // Read data (9 bytes total in register, only the first two bytes contain the temperature)
        for (int i = 0; i < 9; i++) {
            data[i] = ds.read();
        }

        // Convert read data (16 bit signed integer) to a float
        int16_t temp_raw = (data[1] << 8) | data[0];
        float temp_celsius = (float)temp_raw/16.0;

        // Convert temperature to Fahrenheit and add it to our running average
        float temp_fahrenheit = temp_celsius * 1.8 + 32.0;
        avgTemp += temp_fahrenheit;
    }

    // If we didn't catch any devices, return 0.0
    if (deviceCount == 0)
        return 0.0;

    // Compute and return the average
    avgTemp /= deviceCount;
    return avgTemp;
}
//-------------------------------------------------------------------------
float ReadSingleOneWireSensor(OneWire ds)
{
  //--- 18B20 stuff
  byte i;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius = 12.3;

  if (!ds.search(addr))
  {
    ds.reset_search();
    delay(250);
    return celsius;
  }

  if (OneWire::crc8(addr, 7) != addr[7])
  {
    return celsius;
  }

  //--- the first ROM byte indicates which chip
  switch (addr[0])
  {
  case 0x10:
    //Serial.println("  Chip = DS18S20");  // or old DS1820
    type_s = 1;
    break;
  case 0x28:
    // Serial.println("  Chip = DS18B20");
    type_s = 0;
    break;
  case 0x22:
    // Serial.println("  Chip = DS1822");
    type_s = 0;
    break;
  default:
    // Serial.println("Device is not a DS18x20 family device.");
    return celsius;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1 );  //--- start conversion, use alternatively ds.write(0x44,1) with parasite power on at the end

  delay(1000);        //--- maybe 750ms is enough, maybe not
                      //--- we might do a ds.depower() here, but the reset will take care of it.

  ds.reset();         //--- DS18B20 responds with presence pulse
                      //--- match ROM 0x55, sensor sends ROM-code command ommitted here.
  ds.select(addr);
  ds.write(0xBE);     //--- read scratchpad
  for (i = 0; i < 9; i++)
  {
    //--- we need 9 bytes, 9th byte is CRC, first 8 are data
    data[i] = ds.read();
  }

  //--- Convert the data to actual temperature
  //--- because the result is a 16 bit signed integer, it should
  //--- be stored to an "int16_t" type, which is always 16 bits
  //--- even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s)
  {
    raw = raw << 3;     //--- 9 bit resolution default
    if (data[7] == 0x10)
    {
      //--- "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    };
  }
  else
  {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    // default is 12 bit resolution, 750 ms conversion time
    if (cfg == 0x00) raw = raw & ~7;        // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3;   // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1;   // 11 bit res, 375 ms
  };

  celsius = (float)raw / 16.0;    //fahrenheit = celsius * 1.8 + 32.0;

  //---- Check if any reads failed and exit early (to try again).  
  if (isnan(celsius))
  {
    //--- signalize error condition 
    celsius = -99.9;
  };
  return celsius;
}