Xiaomi Flower care + ESP32 / BLE통신

2023. 3. 13. 10:39개발/Arduino

https://www.youtube.com/watch?v=8haDQaKoPL4&t=3s 

https://www.youtube.com/watch?v=DsbhVvrWVCc&t=2s 

오래전에 Xiaomi사의 Flower Care 센서제품의 데이터를

BLE로 ESP32와 연동한 경험이 있다.

 

프로그래밍에 관련해서

정말 단 하나도 모르던 시절에

프로젝트 팀에서 블루투스를 맡게 되었었다.

 

돌이켜 생각해보면 너무 감사한 경험이다.

그때의 난 정말 아무것도 몰랐기에

왜 이렇게 어려운 일을 시키시는거지? 했는데

 

지금 생각해보면 그 시기가 있어서

막막하고 해결책이 보이지 않는 일이 생겨도

당황하거나 포기하지 않으려는 마음이 남아있는 것 같다.

 

저때는 아두이노의 digitalWrite( 핀번호, High ) 에서

핀번호를 입력안해서 동작 안했는데

이 문제로 3시간동안 머리를 싸맬 정도로

무지했다.

 

그런 내가 약 2달에 걸쳐

블루투스 센서값을 성공적으로 추출했으니

그 때의 성취감은 아직 생생하다.

 

아무튼 이 센서를 다시 사용해야될 일이 생겨서

사용했던 소스를 그대로 구동해보았는데

어째서인지 오류가 발생했다.

 

Xiaomi 사의 스마트폰 어플과 센서끼리는

잘 동작하는걸 확인해서

ESP32 소스에 문제가 있다고 생각했다.


- ESP32 소스코드 -

//참조사이트
//https://github.com/SusanneThroner/FlowerCareESP32/blob/master/flowerCareESP32/flowerCareESP32.ino
// 센서 프로토콜 설명  https://github.com/ChrisScheffler/miflora/wiki/The-Basics
#include <ArduinoJson.h>

char* FLORA_DEVICES[] = {"C4:7C:8D:63:92:E5"};//첫번째
#define SLEEP_DURATION 5
#define RETRY 3
#include "BLEDevice.h"
#include "config.h"
RTC_DATA_ATTR int counter = 0;
int battery=0;
String sMac;
char mqttBuffer[100];

// device count
static int deviceCount = sizeof FLORA_DEVICES / sizeof FLORA_DEVICES[0];

// the remote service we wish to connect to
static BLEUUID serviceUUID("00001204-0000-1000-8000-00805f9b34fb");

// the characteristic of the remote service we are interested in
static BLEUUID uuid_version_battery("00001a02-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_sensor_data("00001a01-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_write_mode("00001a00-0000-1000-8000-00805f9b34fb");

//TaskHandle_t hibernateTaskHandle = NULL; 

BLEClient* floraClient;
char* deviceMacAddress;
BLERemoteService* floraService;
BLERemoteCharacteristic* floraCharacteristic;

//void hibernate() {
//  esp_sleep_enable_timer_wakeup(SLEEP_DURATION * 1000000ll);
//  Serial.println("Going to sleep now.");
//  delay(100);
//  esp_deep_sleep_start();
//}

bool readXaiomi01() {
  Serial.print(counter++); Serial.println("   ");
  BLEDevice::init("");
  deviceMacAddress = FLORA_DEVICES[0];
  sMac=String(deviceMacAddress);
  sMac.replace(":","");
  BLEAddress floraAddress(deviceMacAddress);
  BLEClient* floraClient = BLEDevice::createClient();
  floraClient->connect(floraAddress);
  // connect data service
  floraService = floraClient->getService(serviceUUID);
  floraCharacteristic = floraService->getCharacteristic(uuid_write_mode);
  // Real-time data read request
  uint8_t buf[2] = {0xA0, 0x1F};
  floraCharacteristic->writeValue(buf, 2, true);
  floraCharacteristic = floraService->getCharacteristic(uuid_sensor_data);
  std::string value; 
  value = floraCharacteristic->readValue();
  const char *val = value.c_str();
  Serial.print("Hex: ");
  for (int i = 0; i < 16; i++) {
    Serial.print((int)val[i], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  uint16_t temperature = (val[0] + val[1]*256) / ((float)10.0);
  uint8_t moisture = val[7];
  uint16_t light = val[3] + val[4] *256;
  int conductivity = val[8] + val[9] * 256;

  floraCharacteristic = floraService->getCharacteristic(uuid_version_battery);
  std::string value2;
  value2 = floraCharacteristic->readValue();
  delay(1000);
  const char *val2 = value2.c_str();
  int battery = val2[0];

  StaticJsonDocument<200> doc;
  doc["mac"] = sMac;
  doc["temperature"] = temperature;
  doc["moisture"] = moisture; 
  doc["light"] = light; 
  doc["conductivity"] = conductivity;
  doc["battery"] = battery;
  serializeJson(doc, mqttBuffer);
  Serial.println(mqttBuffer);
  floraClient->disconnect();
  // go to sleep now
  //hibernate();
}

void setup() {
  // all action is done when device is woken up
  Serial.begin(115200);
  readXaiomi01();
}

void loop() {
  delay(1000);
}

해당 Xiaomi Flower care 장치의

MAC address와 UUID 값을 기입해주고

UUID value에 접근해 센서값을 받아오는 프로그램이다.

 

이 센서를 다른 프로젝트에서

사용하기도 했고

잘 돌아가던 소스가 오류가 발생했다.

 

- 출력 결과 -

0   
Guru Meditation Error: Core  0 panic'ed (Unhandled debug exception). 
Debug exception reason: Stack canary watchpoint triggered (BTU_TASK) 
Core  0 register dump:
PC      : 0x40083436  PS      : 0x00060436  A0      : 0x80083555  A1      : 0x3ffd0230  
A2      : 0x00000268  A3      : 0x00001400  A4      : 0x00000000  A5      : 0x00000000  
A6      : 0x00001004  A7      : 0x3ffb6c20  A8      : 0x3ffd08c0  A9      : 0x3ffd0850  
A10     : 0x3ffb6c20  A11     : 0x3ffda9d4  A12     : 0x3ffb6388  A13     : 0x00000000  
A14     : 0x00000000  A15     : 0x3ffdc050  SAR     : 0x00000010  EXCCAUSE: 0x00000001  
EXCVADDR: 0x00000000  LBEG    : 0x4008fc84  LEND    : 0x4008fc9a  LCOUNT  : 0xffffffff  


Backtrace:0x40083433:0x3ffd02300x40083552:0x3ffd0260 0x4010dcbb:0x3ffd02b0 0x400e6f25:0x3ffd02e0 0x40113a28:0x3ffd0310 0x40136297:0x3ffd05a0 0x401149da:0x3ffd0830 0x40135e6d:0x3ffd0850 0x401149da:0x3ffd08c0 0x40135ada:0x3ffd08e0 0x40113d39:0x3ffd0900 0x40113da5:0x3ffd0b90 0x40113ee2:0x3ffd0bb0 0x400fed71:0x3ffd0bd0 0x400fa0de:0x3ffd0e70 0x400fa589:0x3ffd1100 0x400faf41:0x3ffd1160 0x400fc27c:0x3ffd11a0 0x400fc2b2:0x3ffd11c0 0x4010750d:0x3ffd11e0 0x400f8098:0x3ffd1370 0x40110b63:0x3ffd1390 




ELF file SHA256: 0000000000000000

Rebooting...

위와 같이 0이 출력되고

일정시간이 지난 뒤 강제 재부팅된다.

센서값이 들어오지도 않은 채 재부팅된다.

Serial.print(counter++); Serial.println("   ");

0 은 counter 값으로 문제없이 출력된다.

아마 BLE 서버 접속 소스쪽에서 오류가 발생하는 것 같다.

오류 메시지를 구글링 해봤다.

 

Guru Meditation Error: Core 0 panic'ed (Unhandled debug exception)

https://github.com/espressif/arduino-esp32/issues/3481

 

wifiMulti : Guru Meditation Error: Core 0 panic'ed (Unhandled debug exception) · Issue #3481 · espressif/arduino-esp32

Here is the problem, i have a Guru Meditation error as soon as i run the wifiMulti.run() In my program. I don't understand why. Here is my current program: `` #include <Arduino.h> #includ...

github.com

다른 사람들도 같은 오류가 발생했다.

BLE 통신을 사용한 나와는 달리

WiFi를 사용한 사람도 같은 오류가 발생했다.

 

다들 하나같이 memory 오류라고 하는데

명확한 해결책이 주어지지는 않는다.

 

ChatGPT도 그냥

 

The "Guru Meditation Error: Core 0 panic'ed (Unhandled debug exception)" error is an indication that the ESP32 has encountered an error and cannot recover. This error can be caused by a variety of factors, including software bugs, memory allocation errors, and hardware issues.

Here are some steps you can take to resolve the issue:

  1. Check your code: The first step is to make sure that your code is correct and there are no syntax or logic errors that might be causing the problem.
  2. Increase memory allocation: If the error is caused by a memory allocation issue, you can try increasing the memory allocation for your program. You can do this by increasing the stack size or heap size of your program.
  3. Update firmware: If the error is caused by a firmware bug, you can try updating the firmware of your ESP32. Check for the latest firmware and make sure you have the latest version installed.
  4. Check hardware: If the error persists, it could be a hardware issue. Check your hardware connections and make sure that everything is properly connected. If you have any other hardware components connected to your ESP32, try removing them one by one to isolate the issue.
  5. Use debugging tools: You can use debugging tools such as the ESP32 Monitor to help diagnose the problem. The monitor can provide useful information about the error and help you identify the root cause.
  6. Seek help: If you have tried all the above steps and are still unable to resolve the issue, you can seek help from the ESP32 community or contact the manufacturer for support.

당연한 소리만 쭈욱 알려준다.


소스코드 수정

그래서 나는 그냥

bool readXaiomi01() {
  Serial.print(counter++); Serial.println("   ");
  BLEDevice::init("");
  Serial.println("1");
  deviceMacAddress = FLORA_DEVICES[0];
  Serial.println("2");
  sMac=String(deviceMacAddress);
  sMac.replace(":","");
  BLEAddress floraAddress(deviceMacAddress);
  Serial.println("3");
  BLEClient* floraClient = BLEDevice::createClient();
  Serial.println("4");
  floraClient->connect(floraAddress);
  Serial.println("5");
  // connect data service
  floraService = floraClient->getService(serviceUUID);
  Serial.println("6");
  floraCharacteristic = floraService->getCharacteristic(uuid_write_mode);
  Serial.println("7");
  // Real-time data read request
  uint8_t buf[2] = {0xA0, 0x1F};
  floraCharacteristic->writeValue(buf, 2, true);
  floraCharacteristic = floraService->getCharacteristic(uuid_sensor_data);
  Serial.println("8");
  std::string value; 
  value = floraCharacteristic->readValue();
  const char *val = value.c_str();
  Serial.print("Hex: ");
  for (int i = 0; i < 16; i++) {
    Serial.print((int)val[i], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  uint16_t temperature = (val[0] + val[1]*256) / ((float)10.0);
  uint8_t moisture = val[7];
  uint16_t light = val[3] + val[4] *256;
  int conductivity = val[8] + val[9] * 256;

  floraCharacteristic = floraService->getCharacteristic(uuid_version_battery);
  std::string value2;
  value2 = floraCharacteristic->readValue();
  const char *val2 = value2.c_str();
  int battery = val2[0];

  StaticJsonDocument<200> doc;
  doc["mac"] = sMac;
  doc["temperature"] = temperature;
  doc["moisture"] = moisture; 
  doc["light"] = light; 
  doc["conductivity"] = conductivity;
  doc["battery"] = battery;
  serializeJson(doc, mqttBuffer);
  Serial.println(mqttBuffer);
  floraClient->disconnect();
  // go to sleep now
  //hibernate();
}

이렇게 코드 사이사이에

Serial.print(1,2,3,4,...) 를 찍어서

어디까지 정상 구동되고

어디부터 오류가 발생하는지 직접 찾기로 했다.

 

 - 출력 결과 -

0   
1
2
3
4
5
Guru Meditation Error: Core  0 panic'ed (Unhandled debug exception). 
Debug exception reason: Stack canary watchpoint triggered (BTU_TASK) 
Core  0 register dump:
PC      : 0x40083436  PS      : 0x00060436  A0      : 0x80083555  A1      : 0x3ffd0230  
A2      : 0x00000268  A3      : 0x00001400  A4      : 0x00000000  A5      : 0x00000000  
A6      : 0x00001004  A7      : 0x3ffb6c20  A8      : 0x3ffd08c0  A9      : 0x3ffd0850  
A10     : 0x3ffb6c20  A11     : 0x3ffda9dc  A12     : 0x3ffb6388  A13     : 0x00000000  
A14     : 0x00000000  A15     : 0x3ffdc058  SAR     : 0x00000010  EXCCAUSE: 0x00000001  
EXCVADDR: 0x00000000  LBEG    : 0x4008fc84  LEND    : 0x4008fc9a  LCOUNT  : 0xffffffff  


Backtrace:0x40083433:0x3ffd02300x40083552:0x3ffd0260 0x4010dd5b:0x3ffd02b0 0x400e6fc1:0x3ffd02e0 0x40113ac8:0x3ffd0310 0x40136337:0x3ffd05a0 0x40114a7a:0x3ffd0830 0x40135f0d:0x3ffd0850 0x40114a7a:0x3ffd08c0 0x40135b7a:0x3ffd08e0 0x40113dd9:0x3ffd0900 0x40113e45:0x3ffd0b90 0x40113f82:0x3ffd0bb0 0x400fee11:0x3ffd0bd0 0x400fa17e:0x3ffd0e70 0x400fa629:0x3ffd1100 0x400fafe1:0x3ffd1160 0x400fc31c:0x3ffd11a0 0x400fc352:0x3ffd11c0 0x401075ad:0x3ffd11e0 0x400f8138:0x3ffd1370 0x40110c03:0x3ffd1390 




ELF file SHA256: 0000000000000000

Rebooting...

Serial.println("5")까지 출력되고

재부팅되는걸 확인했다.

bool readXaiomi01() {
  Serial.print(counter++); Serial.println("   ");
  BLEDevice::init("");
  Serial.println("1");
  deviceMacAddress = FLORA_DEVICES[0];
  Serial.println("2");
  sMac=String(deviceMacAddress);
  sMac.replace(":","");
  BLEAddress floraAddress(deviceMacAddress);
  Serial.println("3");
  BLEClient* floraClient = BLEDevice::createClient();
  Serial.println("4");
  floraClient->connect(floraAddress);
  Serial.println("5");
  // connect data service
  floraService = floraClient->getService(serviceUUID);
  Serial.println("6");
  floraCharacteristic = floraService->getCharacteristic(uuid_write_mode);
  Serial.println("7");
  // Real-time data read request
  uint8_t buf[2] = {0xA0, 0x1F};
  floraCharacteristic->writeValue(buf, 2, true);
  floraCharacteristic = floraService->getCharacteristic(uuid_sensor_data);
  Serial.println("8");

floraClient->connect(floraAddress); 까지 구동 후

floraService = floraClient->getService(serviceUUID); 에서

오류가 발생하는 것 같다.

 

근데 해당 라인은

serviceUUID값이 잘못되지 않는 이상

오류가 발생할게 없는데

 

혹시 몰라서

floraClient->connect(floraAddress);
  Serial.println("5");
  delay(3000);
  // connect data service
  floraService = floraClient->getService(serviceUUID);
  Serial.println("6");

5번과 6번 사이에 딜레이를 넣어봤다.

오류 메시지 구글링했을 때

뭐 메모리 관련 오류다 그랬으니까

 

그냥 생각없이 딜레이를 추가해봤더니

0   
1
2
3
4
5
6
7
8
Hex: F9 0 A0 47 0 0 0 0 0 0 2 3C 0 FB 34 9B  
{"mac":"C47C8D6392E5","temperature":24,"moisture":0,"light":71,"conductivity":0,"battery":100}
Guru Meditation Error: Core  1 panic'ed (InstrFetchProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x00000008  PS      : 0x00060530  A0      : 0x801618a4  A1      : 0x3ffc71c0  
A2      : 0x3ffc7450  A3      : 0x3ffc7220  A4      : 0x3ffc7290  A5      : 0x00000001  
A6      : 0x00000008  A7      : 0x00000000  A8      : 0x80161618  A9      : 0x0000000a  
A10     : 0x00000001  A11     : 0x0000000a  A12     : 0x00000063  A13     : 0x3ffc7450  
A14     : 0x3ffc7450  A15     : 0x3ffc7220  SAR     : 0x00000020  EXCCAUSE: 0x00000014  
EXCVADDR: 0x00000008  LBEG    : 0x40090319  LEND    : 0x40090329  LCOUNT  : 0xffffffff  


Backtrace:0x00000005:0x3ffc71c00x401618a1:0x3ffc7220 0x400d28f3:0x3ffc72c0 0x400d2abb:0x3ffc7470 0x400d7e3a:0x3ffc74a0 




ELF file SHA256: 0000000000000000

Rebooting...

WOW 드디어 다시 동작한다.

온도,습도,일조량,전도율,배터리 값을

Json 데이터로 정상적으로 출력한다.

 

근데 출력하자마자 오류 발생하면서

재부팅 된다.

이건  ESP32 deep sleep 모드로 진입시켜서

안전하게 재부팅하도록 했다.

void hibernate() {
  esp_sleep_enable_timer_wakeup(SLEEP_DURATION * 1000000ll);
  Serial.println("Going to sleep now.");
  delay(100);
  esp_deep_sleep_start();
}

센서값을 받아온 뒤 hibernate() 함수를 실행시켜

일정시간 후 다시 부팅되도록 했다.


최종 결과

1
2
3
4
5
6
7
8
Hex: FC 0 A0 49 0 0 0 0 0 0 2 3C 0 FB 34 9B  
{"mac":"C47C8D6392E5","temperature":25,"moisture":0,"light":73,"conductivity":0,"battery":100}
Going to sleep now.
ets Jun  8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1324
ho 0 tail 12 room 4
load:0x40078000,len:13508
load:0x40080400,len:3604
entry 0x400805f0

위와 같이 Going to sleep now 이후

일정시간이 지나면 다시 구동되어

다시 센서값을 읽어온다.

 

정상적으로 복구했다

같은 센서, 같은 프로그램, 같은 CPU를 사용했는데도

이런 오류가 발생해서 좀 당황스러웠는데

 

메모리 관련 이슈인 것 같다.

일단 Delay로 처리를 하긴 했지만

메모리 오류 관련해서는

정말 깊게 알아봐야될 것 같다.

원인이 눈에 보이질 않아서 너무 어려웠다..

'개발 > Arduino' 카테고리의 다른 글

Lora 및 485 통신  (0) 2023.03.08
ESP32 BLE & RS-232 RS-485통신  (0) 2023.03.02
ESP32 web server  (0) 2023.02.28
성능지표 테스트  (0) 2023.01.10
성능지표 및 Arduino 함수 트리거 처리  (2) 2023.01.04