From 5b7ba95b0c7d1844f5af87ad9bbf7db50d44a619 Mon Sep 17 00:00:00 2001 From: Louis Lagendijk Date: Sat, 12 Jan 2019 22:09:50 +0100 Subject: [PATCH 1/6] Added Max44009 support --- sonoff/i18n.h | 1 + sonoff/xsns_91_max44009.ino | 166 ++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 sonoff/xsns_91_max44009.ino diff --git a/sonoff/i18n.h b/sonoff/i18n.h index a90028e8d..4469ae006 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -549,6 +549,7 @@ const char HTTP_SNS_PRESSURE[] PROGMEM = "%s{s}%s " D_PRESSURE "{m}%s %s{e}"; const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "%s{s}%s " D_PRESSUREATSEALEVEL "{m}%s %s{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_ANALOG[] PROGMEM = "%s{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "%s{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = +const char HTTP_SNS_ILLUMINANCE_S[] PROGMEM = "%s{s}%s " D_ILLUMINANCE "{m}%s " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = #if defined(USE_MHZ19) || defined(USE_SENSEAIR) || defined(USE_AZ7798) const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = diff --git a/sonoff/xsns_91_max44009.ino b/sonoff/xsns_91_max44009.ino new file mode 100644 index 000000000..499a88eb0 --- /dev/null +++ b/sonoff/xsns_91_max44009.ino @@ -0,0 +1,166 @@ +/* + xsns_91_max44009.ino - MAX44009 ambient light sensor support for Sonoff-Tasmota + + Copyright (C) 2019 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_MAX44009 +/*********************************************************************************************\ + * MAX44009 - Ambient Light Intensity + * + * I2C Address: 0x23 or 0x5C +\*********************************************************************************************/ + +#define XSNS_91 91 + +#define MAX44009_ADDR1 0x4A +#define MAX44009_ADDR2 0x4B +#define REG_CONFIG 0x02 +#define REG_LUMINANCE 0x03 +#define MAX44009_CONTINUOUS_AUTO_MODE 0x80 // Start measurement in automatic, continous mode + +uint8_t max44009_address; +uint8_t max44009_addresses[] = { MAX44009_ADDR1, MAX44009_ADDR2 }; +uint8_t max44009_type = 0; +uint8_t max44009_valid = 0; +float max44009_illuminance = 0; +char max44009_types[] = "MAX44009"; + +bool Max4409Read_lum(void) +{ + if (max44009_valid) { max44009_valid--; } + + /* Select luminance start register */ + Wire.beginTransmission(max44009_address); + Wire.write(REG_LUMINANCE); + Wire.endTransmission(); + + if (2 != Wire.requestFrom(max44009_address, (uint8_t)2)) { return false; } + byte msb = Wire.read(); + byte lsb = Wire.read(); + int exponent = (msb & 0xF0) >> 4; + int mantissa = ((msb & 0x0F) << 4) | (lsb & 0x0F); + max44009_illuminance = pow(2, exponent) * mantissa * 0.045; + + max44009_valid = SENSOR_MAX_MISS; + return true; +} + +/********************************************************************************************/ + +void Max4409Detect(void) +{ + if (max44009_type) { + return; + } + + for (byte i = 0; i < sizeof(max44009_addresses); i++) { + max44009_address = max44009_addresses[i]; + Wire.beginTransmission(max44009_address); + + /* select configuration register iand set mode */ + Wire.write(REG_CONFIG); + Wire.write(MAX44009_CONTINUOUS_AUTO_MODE); + if (!Wire.endTransmission()) { + max44009_type = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, max44009_types, max44009_address); + AddLog(LOG_LEVEL_DEBUG); + break; + } + } +} + +void Max4409EverySecond(void) +{ + if (90 == (uptime %100)) { + // 1mS + Max4409Detect(); + } + else { + // 1mS + if (max44009_type) { + if (!Max4409Read_lum()) { + AddLogMissed(max44009_types, max44009_valid); +// if (!max44009_valid) { max44009_type = 0; } + } + } + } +} + +void Max4409Show(boolean json) +{ + char illum_str[8]; + + if (max44009_valid) { + + /* convert illuminance to fixed size string */ + if (max44009_illuminance < 10) { + dtostrf(max44009_illuminance, sizeof(illum_str) -1, 3, illum_str); + } else if (max44009_illuminance < 100) { + dtostrf(max44009_illuminance, sizeof(illum_str) -1, 2, illum_str); + } else if (max44009_illuminance < 1000) { + dtostrf(max44009_illuminance, sizeof(illum_str) -1, 1, illum_str); + } else { + dtostrf(max44009_illuminance, sizeof(illum_str) -1, 0, illum_str); + } + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_ILLUMINANCE "\":%s}"), mqtt_data, max44009_types, illum_str); +#ifdef USE_DOMOTICZ + if (0 == tele_period) { + DomoticzSensor(DZ_ILLUMINANCE, illum_str); + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ILLUMINANCE_S, mqtt_data, max44009_types, illum_str); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +boolean Xsns91(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_INIT: + Max4409Detect(); + break; + case FUNC_EVERY_SECOND: + Max4409EverySecond(); + break; + case FUNC_JSON_APPEND: + Max4409Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + Max4409Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_MAX44009 +#endif // USE_I2C From 7b9c2d6797ee912be2fba61333b65f79893d5cac Mon Sep 17 00:00:00 2001 From: Louis Lagendijk Date: Sat, 12 Jan 2019 23:27:37 +0100 Subject: [PATCH 2/6] Added MAX44009 in my_user_config.h --- sonoff/my_user_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index a4fbfef7a..537aafaef 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -338,7 +338,7 @@ #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module - + #define USE_MAX44009 // Enable MAX44009 sensor ((I2C address 0x4a 0x4b) +5k2 code) #endif // USE_I2C // -- SPI sensors --------------------------------- From 08512fc5fa6ea028edc3da49403ed4578fbbe7f8 Mon Sep 17 00:00:00 2001 From: Louis Lagendijk Date: Sat, 19 Jan 2019 23:27:12 +0100 Subject: [PATCH 3/6] First draft of better MAX44009 detection --- sonoff/xsns_91_max44009.ino | 100 +++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/sonoff/xsns_91_max44009.ino b/sonoff/xsns_91_max44009.ino index 499a88eb0..e113f1e01 100644 --- a/sonoff/xsns_91_max44009.ino +++ b/sonoff/xsns_91_max44009.ino @@ -29,34 +29,47 @@ #define MAX44009_ADDR1 0x4A #define MAX44009_ADDR2 0x4B +#define MAX44009_NO_REGISTERS 8 #define REG_CONFIG 0x02 #define REG_LUMINANCE 0x03 #define MAX44009_CONTINUOUS_AUTO_MODE 0x80 // Start measurement in automatic, continous mode uint8_t max44009_address; -uint8_t max44009_addresses[] = { MAX44009_ADDR1, MAX44009_ADDR2 }; -uint8_t max44009_type = 0; +uint8_t max44009_addresses[] = { MAX44009_ADDR1, MAX44009_ADDR2, 0 }; //0 terminated list +uint8_t max44009_found = 0; uint8_t max44009_valid = 0; float max44009_illuminance = 0; char max44009_types[] = "MAX44009"; bool Max4409Read_lum(void) { - if (max44009_valid) { max44009_valid--; } - + max44009_valid = 0; /* Select luminance start register */ Wire.beginTransmission(max44009_address); Wire.write(REG_LUMINANCE); Wire.endTransmission(); - if (2 != Wire.requestFrom(max44009_address, (uint8_t)2)) { return false; } + if (2 != Wire.requestFrom(max44009_address, (uint8_t)2)) { + return false; + } byte msb = Wire.read(); byte lsb = Wire.read(); int exponent = (msb & 0xF0) >> 4; int mantissa = ((msb & 0x0F) << 4) | (lsb & 0x0F); max44009_illuminance = pow(2, exponent) * mantissa * 0.045; - max44009_valid = SENSOR_MAX_MISS; + max44009_valid = 1; + return true; +} + +bool Max4409Read_register(uint8_t regno, byte *value) { + Wire.beginTransmission(max44009_address); + Wire.write(regno); + if ((0 != Wire.endTransmission()) || + (1 != Wire.requestFrom(max44009_address, (uint8_t)1))) { + return false; + } + *value = (byte)Wire.read(); return true; } @@ -64,23 +77,63 @@ bool Max4409Read_lum(void) void Max4409Detect(void) { - if (max44009_type) { + byte reg[8]; + bool failed = false; + + if (max44009_found) { return; } - for (byte i = 0; i < sizeof(max44009_addresses); i++) { + for (byte i = 0; 0 != max44009_addresses[i]; i++) { max44009_address = max44009_addresses[i]; - Wire.beginTransmission(max44009_address); - /* select configuration register iand set mode */ - Wire.write(REG_CONFIG); - Wire.write(MAX44009_CONTINUOUS_AUTO_MODE); - if (!Wire.endTransmission()) { - max44009_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, max44009_types, max44009_address); + // we need to read each register separately, as auto-increment is only + // supported for illiminance registers + for (byte r = 0; r < MAX44009_NO_REGISTERS; r++) { + if (false == Max4409Read_register(r, ®[r])) { + snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Failed to read register %d", + max44009_address, (int)r); + AddLog(LOG_LEVEL_DEBUG); + failed = true; + break; + } + } + if (failed) { + continue; + } + + snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Read %x %x %x %x %x %x %x %x", + (int) max44009_address, (int)reg[0], (int)reg[1], (int)reg[2], (int)reg[3], + (int)reg[4], (int)reg[5], (int)reg[6], (int)reg[7]); + AddLog(LOG_LEVEL_DEBUG); + + if ( (0x00 == reg[0]) && + (0x00 == reg[1]) && + ( (0x00 == (reg[2] & 0xc0)) || (MAX44009_CONTINUOUS_AUTO_MODE == (reg[2] & 0xc0)) ) && + (0xef == reg[5]) && + (0x00 == reg[6]) && + (0xff == reg[7])) { + + // looks reasonable, try to initialize + + Wire.beginTransmission(max44009_address); + + // select configuration register and set mode + Wire.write(REG_CONFIG); + Wire.write(MAX44009_CONTINUOUS_AUTO_MODE); + if (0 == Wire.endTransmission()) { + max44009_found = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, max44009_types, max44009_address); + AddLog(LOG_LEVEL_DEBUG); + break; + } else { + snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: config failed!", max44009_address); + AddLog(LOG_LEVEL_DEBUG); + } + } else { + snprintf_P(log_data, sizeof(log_data), "Reading initial data failed: No MAX44009 at %x", max44009_address); AddLog(LOG_LEVEL_DEBUG); - break; - } + } } } @@ -92,11 +145,8 @@ void Max4409EverySecond(void) } else { // 1mS - if (max44009_type) { - if (!Max4409Read_lum()) { - AddLogMissed(max44009_types, max44009_valid); -// if (!max44009_valid) { max44009_type = 0; } - } + if (max44009_found) { + Max4409Read_lum(); } } } @@ -143,9 +193,9 @@ boolean Xsns91(byte function) if (i2c_flg) { switch (function) { - case FUNC_INIT: - Max4409Detect(); - break; +// case FUNC_INIT: +// Max4409Detect(); +// break; case FUNC_EVERY_SECOND: Max4409EverySecond(); break; From ee3ab87d07828bca4da1b6693870b0ed2e27e31a Mon Sep 17 00:00:00 2001 From: Louis Lagendijk Date: Wed, 23 Jan 2019 16:06:06 +0100 Subject: [PATCH 4/6] Made requested changes: - Added checks for improved MAX44009 detection - removed HTTP_SNS_ILLUMINANCE_S (show only integer in web-interface) - removed missed readings and repeated detection --- sonoff/i18n.h | 1 - sonoff/my_user_config.h | 2 +- sonoff/xsns_91_max44009.ino | 60 ++++++++++++++++++------------------- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 4469ae006..a90028e8d 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -549,7 +549,6 @@ const char HTTP_SNS_PRESSURE[] PROGMEM = "%s{s}%s " D_PRESSURE "{m}%s %s{e}"; const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "%s{s}%s " D_PRESSUREATSEALEVEL "{m}%s %s{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_ANALOG[] PROGMEM = "%s{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "%s{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_ILLUMINANCE_S[] PROGMEM = "%s{s}%s " D_ILLUMINANCE "{m}%s " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = #if defined(USE_MHZ19) || defined(USE_SENSEAIR) || defined(USE_AZ7798) const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 2c02809f8..65109d3bf 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -342,7 +342,7 @@ #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module - #define USE_MAX44009 // Enable MAX44009 sensor ((I2C address 0x4a 0x4b) +5k2 code) + #define USE_MAX44009 // Enable MAX44009 sensor ((I2C address 0x4a 0x4b) +6k1 code) #endif // USE_I2C // -- SPI sensors --------------------------------- diff --git a/sonoff/xsns_91_max44009.ino b/sonoff/xsns_91_max44009.ino index e113f1e01..596884879 100644 --- a/sonoff/xsns_91_max44009.ino +++ b/sonoff/xsns_91_max44009.ino @@ -22,7 +22,7 @@ /*********************************************************************************************\ * MAX44009 - Ambient Light Intensity * - * I2C Address: 0x23 or 0x5C + * I2C Address: 0x4a or 0x4b \*********************************************************************************************/ #define XSNS_91 91 @@ -91,9 +91,9 @@ void Max4409Detect(void) // supported for illiminance registers for (byte r = 0; r < MAX44009_NO_REGISTERS; r++) { if (false == Max4409Read_register(r, ®[r])) { - snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Failed to read register %d", - max44009_address, (int)r); - AddLog(LOG_LEVEL_DEBUG); + // snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Failed to read register %d", + // max44009_address, (int)r); + // AddLog(LOG_LEVEL_DEBUG_MORE); failed = true; break; } @@ -102,19 +102,22 @@ void Max4409Detect(void) continue; } - snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Read %x %x %x %x %x %x %x %x", - (int) max44009_address, (int)reg[0], (int)reg[1], (int)reg[2], (int)reg[3], - (int)reg[4], (int)reg[5], (int)reg[6], (int)reg[7]); - AddLog(LOG_LEVEL_DEBUG); + // snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Read %x %x %x %x %x %x %x %x", + // (int) max44009_address, (int)reg[0], (int)reg[1], (int)reg[2], (int)reg[3], + // (int)reg[4], (int)reg[5], (int)reg[6], (int)reg[7]); + // AddLog(LOG_LEVEL_DEBUG_MORE); if ( (0x00 == reg[0]) && (0x00 == reg[1]) && - ( (0x00 == (reg[2] & 0xc0)) || (MAX44009_CONTINUOUS_AUTO_MODE == (reg[2] & 0xc0)) ) && - (0xef == reg[5]) && + // reg[2] is written at configuration, so we cannot rely on its value after restart + // reg[3] and reg[4] will always contain lux values + // Datasheet says reg[5] is on power-up is 0xff, but we get 0xef? + // This makes sense as 0xf for exponent means invalid, so we accept both + ( (0xef == reg[5]) || (0xff == reg[5]) ) && (0x00 == reg[6]) && (0xff == reg[7])) { - // looks reasonable, try to initialize + // looks like a MAX44009, try to initialize Wire.beginTransmission(max44009_address); @@ -127,27 +130,20 @@ void Max4409Detect(void) AddLog(LOG_LEVEL_DEBUG); break; } else { - snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: config failed!", max44009_address); - AddLog(LOG_LEVEL_DEBUG); + // snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: config failed!", max44009_address); + // AddLog(LOG_LEVEL_DEBUG_MORE); } } else { - snprintf_P(log_data, sizeof(log_data), "Reading initial data failed: No MAX44009 at %x", max44009_address); - AddLog(LOG_LEVEL_DEBUG); + //snprintf_P(log_data, sizeof(log_data), "Reading initial data failed: No MAX44009 at %x", max44009_address); + //AddLog(LOG_LEVEL_DEBUG_MORE); } } } void Max4409EverySecond(void) { - if (90 == (uptime %100)) { - // 1mS - Max4409Detect(); - } - else { - // 1mS - if (max44009_found) { - Max4409Read_lum(); - } + if (max44009_found) { + Max4409Read_lum(); } } @@ -157,7 +153,7 @@ void Max4409Show(boolean json) if (max44009_valid) { - /* convert illuminance to fixed size string */ + /* convert illuminance to string with suitable accuracy */ if (max44009_illuminance < 10) { dtostrf(max44009_illuminance, sizeof(illum_str) -1, 3, illum_str); } else if (max44009_illuminance < 100) { @@ -169,7 +165,9 @@ void Max4409Show(boolean json) } if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_ILLUMINANCE "\":%s}"), mqtt_data, max44009_types, illum_str); + snprintf_P(mqtt_data, sizeof(mqtt_data), + PSTR("%s,\"%s\":{\"" D_JSON_ILLUMINANCE "\":%s}"), + mqtt_data, max44009_types, illum_str); #ifdef USE_DOMOTICZ if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, illum_str); @@ -177,7 +175,9 @@ void Max4409Show(boolean json) #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ILLUMINANCE_S, mqtt_data, max44009_types, illum_str); + // show integer value for lx on web-server + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ILLUMINANCE, + mqtt_data, max44009_types, (int)max44009_illuminance); #endif // USE_WEBSERVER } } @@ -193,9 +193,9 @@ boolean Xsns91(byte function) if (i2c_flg) { switch (function) { -// case FUNC_INIT: -// Max4409Detect(); -// break; + case FUNC_INIT: + Max4409Detect(); + break; case FUNC_EVERY_SECOND: Max4409EverySecond(); break; From 4cdc3d5404c688a848770c4e04d66854d50e50f0 Mon Sep 17 00:00:00 2001 From: Louis Lagendijk Date: Wed, 23 Jan 2019 22:20:29 +0100 Subject: [PATCH 5/6] Implemented changes suggested by Theo (Thanks!): - use functions from support.ino (had to split reading in Max4409Detect in 2 8 bits reads as the MAX44009 only supports 16 bits reads for luminance registers) - Used the << instead of pow() to save a lot of xompiled code - Improved float -> string conversion along the suggested lines - Code size is now +/- 750 bytes (without other I2C sensors compiled in I think --- sonoff/my_user_config.h | 2 +- sonoff/xsns_91_max44009.ino | 130 +++++++++++++----------------------- 2 files changed, 48 insertions(+), 84 deletions(-) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 65109d3bf..83830916f 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -342,7 +342,7 @@ #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module - #define USE_MAX44009 // Enable MAX44009 sensor ((I2C address 0x4a 0x4b) +6k1 code) + #define USE_MAX44009 // Enable MAX44009 sensor ((I2C address 0x4a 0x4b) +0k8 code) #endif // USE_I2C // -- SPI sensors --------------------------------- diff --git a/sonoff/xsns_91_max44009.ino b/sonoff/xsns_91_max44009.ino index 596884879..a0aa51a47 100644 --- a/sonoff/xsns_91_max44009.ino +++ b/sonoff/xsns_91_max44009.ino @@ -30,8 +30,11 @@ #define MAX44009_ADDR1 0x4A #define MAX44009_ADDR2 0x4B #define MAX44009_NO_REGISTERS 8 -#define REG_CONFIG 0x02 -#define REG_LUMINANCE 0x03 +#define REG_CONFIG 0x02 +#define REG_LUMINANCE 0x03 +#define REG_LOWER_THRESHOLD 0x06 +#define REG_THRESHOLD_TIMER 0x07 + #define MAX44009_CONTINUOUS_AUTO_MODE 0x80 // Start measurement in automatic, continous mode uint8_t max44009_address; @@ -44,33 +47,18 @@ char max44009_types[] = "MAX44009"; bool Max4409Read_lum(void) { max44009_valid = 0; - /* Select luminance start register */ - Wire.beginTransmission(max44009_address); - Wire.write(REG_LUMINANCE); - Wire.endTransmission(); + uint8_t regdata[2]; - if (2 != Wire.requestFrom(max44009_address, (uint8_t)2)) { - return false; + /* Read 2 bytes luminance */ + if (I2cValidRead16((uint16_t *)®data, max44009_address, REG_LUMINANCE)) { + int exponent = (regdata[0] & 0xF0) >> 4; + int mantissa = ((regdata[0] & 0x0F) << 4) | (regdata[1] & 0x0F); + max44009_illuminance = (float)(((0x00000001 << exponent) * (float)mantissa) * 0.045); + max44009_valid = 1; + return true; + } else { + return false; } - byte msb = Wire.read(); - byte lsb = Wire.read(); - int exponent = (msb & 0xF0) >> 4; - int mantissa = ((msb & 0x0F) << 4) | (lsb & 0x0F); - max44009_illuminance = pow(2, exponent) * mantissa * 0.045; - - max44009_valid = 1; - return true; -} - -bool Max4409Read_register(uint8_t regno, byte *value) { - Wire.beginTransmission(max44009_address); - Wire.write(regno); - if ((0 != Wire.endTransmission()) || - (1 != Wire.requestFrom(max44009_address, (uint8_t)1))) { - return false; - } - *value = (byte)Wire.read(); - return true; } /********************************************************************************************/ @@ -84,58 +72,33 @@ void Max4409Detect(void) return; } + uint8_t buffer1; + uint8_t buffer2; for (byte i = 0; 0 != max44009_addresses[i]; i++) { + max44009_address = max44009_addresses[i]; - // we need to read each register separately, as auto-increment is only - // supported for illiminance registers - for (byte r = 0; r < MAX44009_NO_REGISTERS; r++) { - if (false == Max4409Read_register(r, ®[r])) { - // snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Failed to read register %d", - // max44009_address, (int)r); - // AddLog(LOG_LEVEL_DEBUG_MORE); - failed = true; - break; - } - } - if (failed) { - continue; - } - - // snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: Read %x %x %x %x %x %x %x %x", - // (int) max44009_address, (int)reg[0], (int)reg[1], (int)reg[2], (int)reg[3], - // (int)reg[4], (int)reg[5], (int)reg[6], (int)reg[7]); - // AddLog(LOG_LEVEL_DEBUG_MORE); - - if ( (0x00 == reg[0]) && - (0x00 == reg[1]) && - // reg[2] is written at configuration, so we cannot rely on its value after restart - // reg[3] and reg[4] will always contain lux values - // Datasheet says reg[5] is on power-up is 0xff, but we get 0xef? - // This makes sense as 0xf for exponent means invalid, so we accept both - ( (0xef == reg[5]) || (0xff == reg[5]) ) && - (0x00 == reg[6]) && - (0xff == reg[7])) { - - // looks like a MAX44009, try to initialize - - Wire.beginTransmission(max44009_address); - - // select configuration register and set mode - Wire.write(REG_CONFIG); - Wire.write(MAX44009_CONTINUOUS_AUTO_MODE); - if (0 == Wire.endTransmission()) { - max44009_found = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, max44009_types, max44009_address); - AddLog(LOG_LEVEL_DEBUG); - break; - } else { - // snprintf_P(log_data, sizeof(log_data), "MAX44009 at %x: config failed!", max44009_address); - // AddLog(LOG_LEVEL_DEBUG_MORE); - } - } else { - //snprintf_P(log_data, sizeof(log_data), "Reading initial data failed: No MAX44009 at %x", max44009_address); + if ((I2cValidRead8(&buffer1, max44009_address, REG_LOWER_THRESHOLD)) && + (I2cValidRead8(&buffer2, max44009_address, REG_THRESHOLD_TIMER))) { + //snprintf(log_data, sizeof(log_data), "MAX44009 %x: %x, %x", max44009_address, (int)buffer1, (int)buffer2); //AddLog(LOG_LEVEL_DEBUG_MORE); + if ((0x00 == buffer1) && + (0xFF == buffer2)) { + + // looks like a MAX44009, try to initialize + + Wire.beginTransmission(max44009_address); + + // select configuration register and set mode + Wire.write(REG_CONFIG); + Wire.write(MAX44009_CONTINUOUS_AUTO_MODE); + if (0 == Wire.endTransmission()) { + max44009_found = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, max44009_types, max44009_address); + AddLog(LOG_LEVEL_DEBUG); + break; + } + } } } } @@ -154,15 +117,16 @@ void Max4409Show(boolean json) if (max44009_valid) { /* convert illuminance to string with suitable accuracy */ - if (max44009_illuminance < 10) { - dtostrf(max44009_illuminance, sizeof(illum_str) -1, 3, illum_str); - } else if (max44009_illuminance < 100) { - dtostrf(max44009_illuminance, sizeof(illum_str) -1, 2, illum_str); - } else if (max44009_illuminance < 1000) { - dtostrf(max44009_illuminance, sizeof(illum_str) -1, 1, illum_str); - } else { - dtostrf(max44009_illuminance, sizeof(illum_str) -1, 0, illum_str); + + uint8_t prec = 0; + if (10 > max44009_illuminance ) { + prec = 3; + } else if (100 > max44009_illuminance) { + prec = 2; + } else if (1000 > max44009_illuminance) { + prec = 1; } + dtostrf(max44009_illuminance, sizeof(illum_str) -1, prec, illum_str); if (json) { snprintf_P(mqtt_data, sizeof(mqtt_data), From caabada2141d08bcf780118327b2f140299bdf32 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 24 Jan 2019 11:21:16 +0100 Subject: [PATCH 6/6] Update my_user_config.h --- sonoff/my_user_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 83830916f..83bbb7b65 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -328,6 +328,7 @@ // #define USE_PN532_I2C // Enable PN532 - Near Field Communication (NFC) controller (+1k7 code, 164 bytes of mem) // #define USE_PN532_DATA_FUNCTION // Enable PN532 DATA Usage using Sensor15 command (+1k6 code, 316 bytes of mem) // #define USE_PN532_CAUSE_EVENTS // Enable PN532 driver to cause event's on card read in addition to immediate telemetry (+64 bytes code, 48 bytes mem) +// #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) // #define USE_DISPLAY // Add I2C Display Support (+2k code) #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 @@ -342,7 +343,6 @@ #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module - #define USE_MAX44009 // Enable MAX44009 sensor ((I2C address 0x4a 0x4b) +0k8 code) #endif // USE_I2C // -- SPI sensors ---------------------------------