if (TimeToUpdate)
{
reset_RTC_counter();
ESP.deepSleep(FAST_SLEEP_TIME*1000000); //uS
}
else
{
if (boot_counter>=5)
{
reset_RTC_counter();
ESP.deepSleep(SLEEP_TIME*1000000);
}
else ESP.deepSleep(SLEEP_TIME*1000000, WAKE_RF_DISABLED);
}
void reset_RTC_counter(void)
{
uint32_t bootcount =0;
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
}
uint16_t RTC_bootcount(void)
{
uint32_t bootcount;
uint16_t low_word;
uint16_t high_word;
uint16_t return_word;
ESP.rtcUserMemoryRead(0, &bootcount, sizeof(bootcount));
low_word = bootcount & 0xFFFF;
high_word = (bootcount>>16) & 0xFFFF;
if (low_word!=high_word)
{
low_word = 0;
high_word = 0;
}
return_word = low_word;
low_word++;
high_word++;
bootcount = (high_word << 16) + low_word;
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
return (return_word);
}
void SaveFloatRtc(float fnum1, float fnum2)
{
union
{
uint32_t ltemp;
float ftemp;
};
ftemp = fnum1;
ESP.rtcUserMemoryWrite(1, & ltemp, sizeof(ltemp));
ftemp = fnum2;
ESP.rtcUserMemoryWrite(2, & ltemp, sizeof(ltemp));
}
float GetFloatFromRtc(uint8_t offset)
{
union
{
uint32_t ltemp;
float ftemp;
};
ESP.rtcUserMemoryRead(offset+1, & ltemp, sizeof(ltemp));
return ftemp;
}
mqtt:
sensor:
- name: "Temperature outside"
state_topic: "garage/sensor/temperature/outside"
unit_of_measurement: "°C"
- name: "Temperature inside"
state_topic: "garage/sensor/temperature/inside"
unit_of_measurement: "°C"
- name: "Battery Voltage"
state_topic: "garage/sensor/battery_level"
unit_of_measurement: "V"
- name: "Temperature boiler"
state_topic: "workshop/sensor/temperature/boiler"
unit_of_measurement: "°C"
- name: "Temperature workshop"
state_topic: "workshop/sensor/temperature/inside"
unit_of_measurement: "°C"
- name: "Workshop Battery Voltage"
state_topic: "workshop/sensor/battery_level"
unit_of_measurement: "V"
icon: mdi:battery-60
#include <Arduino.h>
#include <Wire.h>
#include <DS18B20.h>
#include <ESP8266WiFi.h>
#include <ArduinoMqttClient.h>
#define DEBUG false
#define Serial if(DEBUG)Serial
#define TMP75_ADDRESS 0x48
#define TMP75_TEMP_REGISTER 0
#define TMP75_CONF_REGISTER 1
#define TMP75_THYST_REGISTER 2
#define TMP75_TOS_REGISTER 3
#define TMP75_CONF_SHUTDOWN 0
#define TMP75_CONF_OS_COMP_INT 1
#define TMP75_CONF_OS_POL 2
#define TMP75_CONF_OS_F_QUE 3
// time in seconds
//#define SLEEP_TIME 60
#define SLEEP_TIME 600
#define FAST_SLEEP_TIME 10
#define GARAGE 1
// ADC caluibration
#ifdef GARAGE
#define CALIB_CODE 0x2AA
#define CALIB_VOLTAGE 2.78
#else
#define CALIB_CODE 0x2ee
#define CALIB_VOLTAGE 3.06
#endif
const char* ssid = "xxxxxx";
const char* password = "xxxxxxxx";
const int channel = 1;
const uint8_t bssid[] = {0xC8, 0x60, 0x00, 0x94, 0x9B, 0x12};
#ifdef GARAGE
IPAddress ip(192, 168, 0, 150);
#else
IPAddress ip(192, 168, 0, 151);
#endif
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
//IPAddress dns(1,1,1,1);
IPAddress dns(192,168,0,1);
// We make a structure to store connection information
// The ESP8266 RTC memory is arranged into blocks of 4 bytes. The access methods read and write 4 bytes at a time,
// so the RTC data structure should be padded to a 4-byte multiple.
struct
{
uint32_t crc32; // 4 bytes
uint8_t channel; // 1 byte, 5 in total
uint8_t ap_mac[6];// 6 bytes, 11 in total
uint8_t padding; // 1 byte, 12 in total
} rtcData;
const char* mqtt_broker = "192.168.0.253";
const int mqtt_port = 1883;
const char* mqtt_username = "homeassistant";
const char* mqtt_password = "quo8gaelai6zah4uthaefaer4theilai0oth0Cai0phoopahShungie5ohs4Chee";
#ifdef GARAGE
const char *topic[] = {"garage/sensor/temperature/inside",
"garage/sensor/temperature/outside",
"garage/sensor/battery_level"};
#else
const char *topic[] = {"workshop/sensor/temperature/inside",
"workshop/sensor/temperature/boiler",
"workshop/sensor/battery_level"};
#endif
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
//uint8_t ds_address[] = {0x28, 0x69, 0xD8, 0x13, 0x00, 0x00, 0x00, 0x9B};
#ifdef GARAGE
uint8_t ds_address[] = {0x28, 0x13, 0xec, 0x13, 0x00, 0x00, 0x00, 0x57};
#else
uint8_t ds_address[] = {0x28, 0x69, 0xD8, 0x13, 0x00, 0x00, 0x00, 0x9B};
#endif
void TMP75_ctrl(uint8_t ctrl)
{
Wire.begin(); // Join the I2C bus as a master
Wire.beginTransmission(TMP75_ADDRESS); // Address the TMP75 sensor
Wire.write(TMP75_CONF_REGISTER); // Address the Configuration register
Wire.write(ctrl); // Set the temperature resolution
Wire.endTransmission(); // Stop transmitting
}
float readTemp()
{
uint16_t regdata = 0xFFFF;
TMP75_ctrl(0xA1); // One-Shot
Wire.beginTransmission(TMP75_ADDRESS);
Wire.write(TMP75_TEMP_REGISTER); // pointer reg
Wire.endTransmission();
Wire.requestFrom(TMP75_ADDRESS, 2);
regdata = Wire.read();
regdata <<= 8;
regdata |= ((uint16_t)Wire.read());
return ((float)(int16_t)regdata / 32) / 8;
}
void reset_RTC_counter(void)
{
uint32_t bootcount =0;
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
}
uint16_t RTC_bootcount(void)
{
uint32_t bootcount;
uint16_t low_word;
uint16_t high_word;
uint16_t return_word;
ESP.rtcUserMemoryRead(0, &bootcount, sizeof(bootcount));
low_word = bootcount & 0xFFFF;
high_word = (bootcount>>16) & 0xFFFF;
if (low_word!=high_word)
{
low_word = 0;
high_word = 0;
}
return_word = low_word;
low_word++;
high_word++;
bootcount = (high_word << 16) + low_word;
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
return (return_word);
}
void SaveFloatRtc(float fnum1, float fnum2)
{
union
{
uint32_t ltemp;
float ftemp;
};
ftemp = fnum1;
ESP.rtcUserMemoryWrite(1, & ltemp, sizeof(ltemp));
ftemp = fnum2;
ESP.rtcUserMemoryWrite(2, & ltemp, sizeof(ltemp));
}
float GetFloatFromRtc(uint8_t offset)
{
union
{
uint32_t ltemp;
float ftemp;
};
ESP.rtcUserMemoryRead(offset+1, & ltemp, sizeof(ltemp));
return ftemp;
}
uint32_t calculateCRC32( const uint8_t *data, size_t length )
{
uint32_t crc = 0xffffffff;
while( length-- )
{
uint8_t c = *data++;
for( uint32_t i = 0x80; i > 0; i >>= 1 )
{
bool bit = crc & 0x80000000;
if(c & i) bit = !bit;
crc <<= 1;
if(bit) crc ^= 0x04c11db7;
}
}
return crc;
}
void setup_wifi()
{
// Try to read WiFi settings from RTC memory
bool rtcValid = false;
if( ESP.rtcUserMemoryRead( 3, (uint32_t*)&rtcData, sizeof( rtcData ) ) )
{
// Calculate the CRC of what we just read from RTC memory, but skip the first 4 bytes as that's the checksum itself.
uint32_t crc = calculateCRC32( ((uint8_t*)&rtcData) + 4, sizeof( rtcData ) - 4 );
if(crc == rtcData.crc32) rtcValid = true;
}
if (rtcValid) { Serial.print("WiFi settings ok"); }
else { Serial.print("WiFi settings fail"); }
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.config(ip, gateway, subnet, dns);
if(rtcValid) WiFi.begin( ssid, password, rtcData.channel, rtcData.ap_mac, true );
else WiFi.begin(ssid, password);
uint8_t trial_counter=10;
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
trial_counter--;
if (trial_counter==0)
{
Serial.println();
Serial.println("WiFi not availale");
Serial.println("Deep sleep");
rtcData.crc32++; // now crc is wrong
ESP.rtcUserMemoryWrite( 3, (uint32_t*)&rtcData, sizeof( rtcData ) );
//reset_RTC_counter();
ESP.deepSleep(SLEEP_TIME*1000000);
}
}
if (!rtcValid)
{
// Write current connection info back to RTC
rtcData.channel = WiFi.channel();
memcpy(rtcData.ap_mac, WiFi.BSSID(), 6); // Copy 6 bytes of BSSID (AP's MAC address)
rtcData.crc32 = calculateCRC32( ((uint8_t*)&rtcData) + 4, sizeof( rtcData ) - 4 );
ESP.rtcUserMemoryWrite( 3, (uint32_t*)&rtcData, sizeof(rtcData));
}
Serial.println();
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("nWiFi channel: ");
Serial.println(WiFi.channel());
Serial.print("WiFi BSSID: ");
Serial.println(WiFi.BSSIDstr().c_str());
}
#define ONE_WIRE_GPIO 12
//DS18B20 ds(D6); // GPI12
DS18B20 ds(ONE_WIRE_GPIO);
void setup()
{
float SensValues[3];
bool TimeToUpdate = false;
Serial.begin(115200);
delay(100);
Serial.println();
uint16_t boot_counter;
boot_counter = RTC_bootcount();
Serial.println();
Serial.print("Boot count ");
Serial.println(boot_counter);
Wire.begin();
Wire.setClock(400000);
//TMP75_ctrl(0x01); // SD mode 0.5C
TMP75_ctrl(0x21); // SD mode 0.25C
float prevT0 = GetFloatFromRtc(0);
float prevT1 = GetFloatFromRtc(1);
Serial.print("T©=");
// check TMP75
SensValues[0] = readTemp();
Serial.print(SensValues[0]);
Serial.print(", ");
// check DS18B20
if (ds.select(ds_address)) SensValues[1] = ds.getTempC();
else Serial.println("DS18B20 not found!");
Serial.println(SensValues[1]);
if(abs(prevT0-SensValues[0])>0.5) TimeToUpdate = true;
if(abs(prevT1-SensValues[1])>0.5) TimeToUpdate = true;
if (boot_counter==0)
{
setup_wifi() ;
delay(100);
//uint16_t batterylevel = ESP.getVcc();
pinMode(14, OUTPUT);
digitalWrite(14, HIGH);
uint16_t batterylevel = analogRead(A0);
Serial.print("ADC=0x");
Serial.print(batterylevel, HEX);
SensValues[2] = (float)batterylevel/CALIB_CODE*CALIB_VOLTAGE;
Serial.print(", V=");
Serial.println(SensValues[2]);
mqttClient.setUsernamePassword(mqtt_username, mqtt_password);
if (mqttClient.connect(mqtt_broker))
{
Serial.println("You're connected to the MQTT broker!");
for(uint8_t i=0; i<3; i++)
{
mqttClient.beginMessage(topic[i]);
mqttClient.print(SensValues[i]);
mqttClient.endMessage();
delay(10);
}
SaveFloatRtc(SensValues[0], SensValues[1]);
mqttClient.poll();
TimeToUpdate = false;
delay(500);
}
else
{
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
}
}
Serial.println("Deep sleep mode");
if (TimeToUpdate)
{
reset_RTC_counter();
ESP.deepSleep(FAST_SLEEP_TIME*1000000); //uS
}
else
{
if (boot_counter>=5)
{
reset_RTC_counter();
ESP.deepSleep(SLEEP_TIME*1000000);
}
else ESP.deepSleep(SLEEP_TIME*1000000, WAKE_RF_DISABLED); // WAKE_RF_DISABLED
}
}
void loop() {}
+157 |
1571
81
|
+12 |
1446
44
|
+60 |
4152
87
|
Недавно, одна крупная контора, выпустила видеокарты. И там были танталовые конденсаторы. Только они перепутали полярность, при их запайке на плату видеокарты.
утечка если не в ту сторону бешеная.Попробуйте сами и убедитесь.
у меня был случай когда некоторые из одной партии были маркированы наоборот.
При включении перегрев и «волшебный» дым.
С тех пор всегда сначала проверяю тестером.
После покупки перемаркированных танталлов на Али — больше их не беру там принципиально.
:)
Особых трудностей не испытывал.
Да, проектирование сложных деталей в OpenSCAD может быть затруднительным, но простые создаются достаточно быстро.
Вопрос тут в другом — а нужны ли они? Я последнее время печатаю соплом 0.6 мм, оно автоматически дает скругление радиусом 0.3 мм у любого угла. Для большинства задач этого достаточно.
P.S. В модели выше фаски не нужны, т.к. у неё очень специфическое применение.
Логика была, что просыпался раз в 1 минуту, проверял состояние и если все сухо, то дальше в глубокий сон.
А на приёме схожий девайс просыпался раз в 5 минут и если получал аларм, то включал реле и перекрывал воду.
Но я не умею работать с регистром и просто в EPROM писал переменную и когда она достигала 10, то подключался к wifi и говорил что жив и принимал, если надо, новые данные о длительности сна и если надо переводилась в режим прошивки по воздуху.
Питал напрямую от аккумулятора LiOn (4.2v). Плата нормально на этом напряжении работала.
Не смог победить, чтобы ещё напряжение аккумулятора мерить и направлять, это уже обвязки требовало. А так во сне 16мкА ело всего.
Прототип собрал, вроде всё ок и на этом успокоился и купил нормальные датчики aquara на зигби, а на клапан батарею большую (на 3 недели хватает заряда).
В итоге получил интересный опыт работы с esp8266, но понял, что Esp32 рулит, а по энергоэффективности всеже зигби удобнее.
Конечно, наличие любого такого датчика в любом случае лучше, чем его отсутствие. И во многих случаях, когда подкапывает, такое время опроса не критично. Но именно по поводу датчиков протечки, особенно, если есть ещё и приводы, я бы крепко подумал о частоте опроса.
А уже «куда надо» он может сообщать «для сведения, в части касающейся»…
Ну и на аккумуляторах конечно не 1.2 В на самом деле, а 1.4 на старте.
Собственно, моя первоначальная реплика была просто предположением, я не могу отвечать за автора, но исхожу из того, что он опытный разработчик «железа», работавший в супер крутой корпорации TI, куда не всякого возьмут. И дополнительный чип поставил не просто так, а со смыслом. Помимо «высасывания» энергии, кстати, не забудьте фактор стабилизации напряжения, без которого то или иное устройство может преподнести сюрпризы.
В данном обзоре написано:
Итого, 12.36*70 + 181 = 1046 мАч. Примерно столько вы получили от элементов питания. А это половина или даже меньше. То, что у вас один элемент «потек» и внутреннее сопротивление увеличилось до 0.5 Ом — вопрос отдельный, причины которого надо изучать. Но по цифрам вы потратили меньше половины емкости батареек, что примерно соответствует финальному напряжению.
Оптимальным решением будет, скорее всего, таймер + преобразователь, т.к. это позволит снизить ток сна и иметь стабильное питание. Но сильно ли таймер нужен? Допустим, преобразователь потребляет те самые 16 мкА. Это 140 мАч в год. Или 5-7% емкости батарей. Если ESP во сне потребляет еще столько же, это 10-15% емкости в сумме.
Есть ли смысл в оптимизации? Боюсь, что нет, т.к. срок службы батарей определяется не только емкостью, сделать устройство, которое отработает от одного комплекта 10 лет всё равно не выйдет (и ваш опыт с потекшей батарейкой это только доказывает).
А это значит, что питая от 3В вплоть до 0.5Ом внутреннего сопротивления преобразователь был не нужен.
В моем случае таймер решал не только ток сна но и проблему бесконечного сброса.
Если очень хочется таки преобразователь, то его можно управлять именно таким таймером как у меня.
Подсчёт вами емкости в активном режиме оптимистично занижен, т.к. в течении 5 секунд активности esp имеет пики до 140мА.
Смысл оптимизации есть. Если не уходить в зигби или блэ а цепко держаться за старый esp то стоит посмотреть esp now, где активность радио будет не 5 сек а единицы миллисекунд, и о чудо, двух АА хватит существенно на дольше. Моё ИМХО
Помню, когда сделал и повесил, то делал ставки: ну на 2 недели. Ну месяц, ну 2 месяца, ну ок, три. Ну полгода продержится и хорошо:) Когда прошёл год, то уже стало интересно как долго :)
сам не проверял, но попробую когда-нибудь.
там же отдельное ядро под это дело со своим программированием.
хабр это в конце концов или не хабр…
ой сорри ошибся окошком :) :)
Есть у меня весы Xiaomi body composition 2. И я, когда меряю, пускаю прогу для пересылки данных в Гармин.
Есть у меня пара модулей WeMos d1 Mini. Один взял для превращения кофемашины в умную, а второй — чтобы не брать один, авось пригодится.
И вот думаю присобачить к этим весам. Все равно гонять Хоум ассистент, так что думаю, почему бу не запустить скрипт, который будет с помощью внешнего есп-модуля получать по блютузу данные.
На гитхабе рассказано как засунуть этот модуль в отдельную коробку, а я чешу репу.
И вот не знаю, насколько идея тупа, встроить модуль прямо в весы, запитав от батареек.
Там 3 или 4 АА, питания должно хватить. Но будет сажать.
Можно ли сделать так, чтобы модуль был в глубокой спячке, а включался только тогда, когда загорается определенный сегмент индикатора весов (ещё не разбирал и не замерял, сколько туда идёт вольт и модно ли сегмент отделить от остальных)?
Я вижу так сценарий: весы спят. Я или кто-то из семьи становится на весы. Когда вес измеряется до самого конца (с измерением всех этих сопротивлений ступней), там бежит строка из сегментов индикатора. И если последний загорается, чтобы модуль просыпался, грузился, подключался к вайфаю, опрашивал по BLE весы (благо те доступны ещё минут десять после взвешивания), отсылал данные, а потом снова уходил в спячку.
Я не программировал пока ардуинки, не знаю, насколько «пробуждение по вольтажу» вообще возможно. Если да, то буду ковырять.
Вот тут сам проект. В принципе, ничего не мешает подключить «как есть», будет сажать изредка батарейку, включаясь раз в 7 минут, но хотелось бы целенаправленно.
Откуда взялся год? Почему не пол-года и не 5 лет?
А тут автор пишет про просыпания раз в 10 минут, и у меня большие сомнения что это у него долго протянет.
У меня в примерно таком же режиме работы, ЕСП запитанной напрямую от одной 18650 на год автономности не хватает.
Но раз в 10 минут, в течение года — это не 8 а 80+ тысяч )
Так сколько у вас реальное время жизни от батареек? Или не было тестов еще?
После сна порт станет на вход?
Или в «0»?
А после сна и сброса она будет входом.
Они устанавливаются в недоступные?
BL8530 по даташиту выпускаются на фиксированные напряжения (36 вариантов) и для каждого напряжения ещё бывает 6 разновидностей чипа. Итого: 6^3 (216) вариантов. Поэтому выбирать на Али по буквам «BL8530» надо осторожненько… ;)
Если вас интересует именно WiFi розетка, то вот раздел с розетками.
грунтовую батарею забыл на меди и цинке ))
arduinodiy.wordpress.com/2020/01/18/very-deepsleep-and-energy-saving-on-esp8266/
Примеры там присутствуют.
Потом можно узнать, почему датчики температуры ds18b20 не лучший выбор:
community.alexgyver.ru/threads/meteostancija-narodnogo-monitoringa.3529/
Готовый вариант внешнего датчика:
github.com/ghmartin77/ESP8266_BME280
Ну и хороший датчик в метеостанции Андрея Ушакова в Ютубе.
www.youtube.com/watch?v=WZ4iBk451jE
Нормальный это выбор, если читать документацию, думать головой и не «задирать» точность измерений этого датчика до максимальной там, где она на фиг не сдалась…
Персистентный режим позволяет за 0.6 с. реконнектиться вместо обычных 4.5 с., но у вас он не реализован, плюс в библиотеке ESP8266WiFi.h есть баг.
В теории, время тратится на сканирование каналов, на обмен ключами WiFi и на получение IP по dhcp. Первое и третье решается явной передачей параметров, со вторым непонятно.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.