Skip to content

Commit 6cb5e3e

Browse files
committed
v1.4.0
- restructure library - add platformio configuration for testing - set default MTU to 517 - add QR links - add hourly forecast data - add remote touch
1 parent e521f70 commit 6cb5e3e

File tree

9 files changed

+250
-32
lines changed

9 files changed

+250
-32
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11

22
*.py
3+
.pio
4+
.vscode
5+
6+
navigation.txt

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Setup your ESP32 as a smartwatch and connect to Chronos app over BLE.
1212
- [x] Notifications
1313
- [x] Weather
1414
- [x] Controls (Music, Find Phone, Camera)
15+
- [x] Phone Battery (Level, Charging state) (Chronos app v3.5.1+)
1516
- [ ] Alarms
1617

1718
## Companion App
@@ -39,14 +40,15 @@ bool isCameraReady();
3940
4041
// notifications
4142
int getNotificationCount();
42-
Notification getNotificationAt(int index);
43+
Notification getNotificationAt(int index); // index [0-9]
4344
void clearNotifications();
4445
4546
// weather
4647
int getWeatherCount();
4748
String getWeatherCity();
4849
String getWeatherTime();
49-
Weather getWeatherAt(int index);
50+
Weather getWeatherAt(int index); // index[0-6]
51+
HourlyForecast getForecastHour(int hour); // hour [0-23]
5052
5153
// alarms
5254
Alarm getAlarm(int index);
@@ -68,6 +70,9 @@ uint8_t getPhoneBattery();
6870
int getAppCode();
6971
String getAppVersion();
7072
73+
RemoteTouch getTouch(); // RemoteTouch(bool state, uint32_t x, uint32_t y)
74+
String getQrAt(int index); // index [0-8]
75+
7176
// helper functions for ESP32Time
7277
int getHourC(); // return hour based on hour 24 variable
7378
String getHourZ(); // return zero padded hour string based on hour 24 variable
@@ -81,6 +86,10 @@ void setDataCallback(void (*callback)(uint8_t *, int));
8186
void setRawDataCallback(void (*callback)(uint8_t *, int));
8287
```
8388

89+
## PlatformIO
90+
91+
Open the project folder in VS Code with PlatformIO installed to directly run the example sketches. This makes it easier to develop and test features
92+
8493
## Dependencies
8594
- [`ESP32Time`](https://github.com/fbiego/ESP32Time)
8695
- [`NimBLE-Arduino`](https://github.com/h2zero/NimBLE-Arduino)

examples/watch/watch.ino

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ void configCallback(Config config, uint32_t a, uint32_t b)
212212
case CF_PBAT:
213213
// state is saved internally
214214
Serial.print("Phone battery: ");
215-
Serial.println(a == 1 ? "Charging" : "Not Charing"); // bool state = watch.isPhoneCharging();
215+
Serial.println(a == 1 ? "Charging" : "Not Charging"); // bool state = watch.isPhoneCharging();
216216
Serial.print("Level: ");
217217
Serial.print(b); // uint8_t level = watch.getPhoneBattery();
218218
Serial.println("%");
@@ -224,6 +224,20 @@ void configCallback(Config config, uint32_t a, uint32_t b)
224224
Serial.print(" Version: ");
225225
Serial.println(watch.getAppVersion());
226226
break;
227+
case CF_QR:
228+
// qr links
229+
if (a == 0){
230+
// individual qr links (b is the index)
231+
Serial.print("QR code: ");
232+
Serial.println(watch.getQrAt(b));
233+
}
234+
if (a == 1)
235+
{
236+
// end of qr links transmission
237+
Serial.print("QR Links received. Count: ");
238+
Serial.println(b);
239+
}
240+
break;
227241
case CF_WEATHER:
228242
// weather is saved
229243
Serial.println("Weather received");
@@ -292,6 +306,7 @@ void setup()
292306
watch.setDataCallback(dataCallback);
293307

294308
watch.begin(); // initializes the BLE
309+
// make sure the ESP32 is not paired with your phone in the bluetooth settings
295310
// go to Chronos app > Watches tab > Watches button > Pair New Devices > Search > Select your board
296311
// you only need to do it once. To disconnect, click on the rotating icon (Top Right)
297312

keywords.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,18 @@ capturePhoto KEYWORD2
3131
setNotifyBattery KEYWORD2
3232
isPhoneCharging KEYWORD2
3333
getPhoneBattery KEYWORD2
34+
getForecastHour KEYWORD2
35+
getTouch KEYWORD2
36+
getQrAt KEYWORD2
3437

3538
Notification LITERAL1
3639
Alarm LITERAL1
3740
Weather LITERAL1
3841
ChronosTimer LITERAL1
3942
ChronosData LITERAL1
4043
ChronosScreen LITERAL1
44+
RemoteTouch LITERAL1
45+
HourlyForecast LITERAL1
4146

4247
MUSIC_PLAY LITERAL1
4348
MUSIC_PAUSE LITERAL1
@@ -67,6 +72,7 @@ CF_WEATHER LITERAL1
6772
CF_CAMERA LITERAL1
6873
CF_PBAT LITERAL1
6974
CF_APP LITERAL1
75+
CF_QR LITERAL1
7076

7177
CS_0x0_000_CFF LITERAL1
7278
CS_240x240_130_STF LITERAL1

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ChronosESP32",
3-
"version": "1.3.0",
3+
"version": "1.4.0",
44
"keywords": "Arduino, ESP32, Time, BLE, Watch",
55
"description": "A library for ESP32 to interface with Chronos app over BLE",
66
"repository":

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=ChronosESP32
2-
version=1.3.0
2+
version=1.4.0
33
author=fbiego
44
maintainer=fbiego
55
sentence=Setup your ESP32 as a smartwatch and connect to Chronos app over BLE.

platformio.ini

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; PlatformIO Project Configuration File
2+
;
3+
; Build options: build flags, source filter
4+
; Upload options: custom upload port, speed and extra flags
5+
; Library options: dependencies, extra library storages
6+
; Advanced options: extra scripting
7+
;
8+
; Please visit documentation for the other options and examples
9+
; https://docs.platformio.org/page/projectconf.html
10+
11+
[platformio]
12+
default_envs = esp32dev
13+
14+
; Uncomment only one to test
15+
src_dir = examples/watch
16+
; src_dir = examples/camera
17+
; src_dir = examples/control
18+
19+
20+
[env]
21+
platform = espressif32
22+
framework = arduino
23+
24+
lib_deps =
25+
; use src folder as library
26+
file://./src
27+
; external library dependencies
28+
fbiego/ESP32Time@^2.0.6
29+
h2zero/NimBLE-Arduino@^1.4.1
30+
31+
[env:esp32dev]
32+
board = esp32dev
33+
34+
[env:devkit]
35+
board = esp32doit-devkit-v1
36+
37+

ChronosESP32.cpp renamed to src/ChronosESP32.cpp

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ ChronosESP32::ChronosESP32()
4343
{
4444
connected = false;
4545
cameraReady = false;
46+
batteryChanged = true;
47+
qrLinks[0] = "https://chronos.ke/";
4648
}
4749

4850
/*!
@@ -64,6 +66,7 @@ void ChronosESP32::begin()
6466
{
6567
BLEDevice::init(watchName.c_str());
6668
BLEServer *pServer = BLEDevice::createServer();
69+
BLEDevice::setMTU(517);
6770
pServer->setCallbacks(this);
6871

6972
BLEService *pService = pServer->createService(SERVICE_UUID);
@@ -269,6 +272,16 @@ Weather ChronosESP32::getWeatherAt(int index)
269272
return weather[index % WEATHER_SIZE];
270273
}
271274

275+
/*!
276+
@brief return the weatherforecast for the hour
277+
@param hour
278+
position of the weather to be returned
279+
*/
280+
HourlyForecast ChronosESP32::getForecastHour(int hour)
281+
{
282+
return hourlyForecast[hour % FORECAST_SIZE];
283+
}
284+
272285
/*!
273286
@brief get the alarm at the index
274287
@param index
@@ -398,6 +411,25 @@ String ChronosESP32::getAmPmC(bool caps)
398411
return "";
399412
}
400413

414+
415+
/*!
416+
@brief get remote touch data
417+
*/
418+
RemoteTouch ChronosESP32::getTouch()
419+
{
420+
return touch;
421+
}
422+
423+
/*!
424+
@brief get the qr link at the index
425+
@param index
426+
position of the qr link to be returned
427+
*/
428+
String ChronosESP32::getQrAt(int index)
429+
{
430+
return qrLinks[index % QR_SIZE];
431+
}
432+
401433
/*!
402434
@brief set the connection callback
403435
*/
@@ -451,7 +483,7 @@ void ChronosESP32::setRawDataCallback(void (*callback)(uint8_t *, int))
451483
*/
452484
void ChronosESP32::sendInfo()
453485
{
454-
uint8_t infoCmd[] = {0xab, 0x00, 0x11, 0xff, 0x92, 0xc0, 0x01, 0x00, 0x00, 0xfb, 0x1e, 0x40, 0xc0, 0x0e, 0x32, 0x28, 0x00, 0xe2, screenConf, 0x80};
486+
uint8_t infoCmd[] = {0xab, 0x00, 0x11, 0xff, 0x92, 0xc0, LIB_VER_MAJOR, (LIB_VER_MINOR * 10 + LIB_VER_PATCH), 0x00, 0xfb, 0x1e, 0x40, 0xc0, 0x0e, 0x32, 0x28, 0x00, 0xe2, screenConf, 0x80};
455487
sendCommand(infoCmd, 20);
456488
}
457489

@@ -590,6 +622,7 @@ void ChronosESP32::onDisconnect(BLEServer *pServer)
590622
connected = false;
591623
cameraReady = false;
592624
BLEDevice::startAdvertising();
625+
touch.state = false; // release touch
593626
if (connectionChangeCallback != nullptr)
594627
{
595628
connectionChangeCallback(false);
@@ -927,6 +960,40 @@ void ChronosESP32::dataReceived()
927960
configurationReceivedCallback(CF_FONT, color, select);
928961
}
929962
break;
963+
case 0xA8:
964+
if (incomingData.data[3] == 0xFE)
965+
{
966+
// end of qr data
967+
int size = incomingData.data[5]; // number of links received
968+
if (configurationReceivedCallback != nullptr)
969+
{
970+
configurationReceivedCallback(CF_QR, 1, size);
971+
}
972+
}
973+
if (incomingData.data[3] == 0xFF)
974+
{
975+
// receiving qr data
976+
int index = incomingData.data[5]; // index of the curent link
977+
qrLinks[index] = ""; // clear existing
978+
for (int i = 6; i < len; i++)
979+
{
980+
qrLinks[index] += (char)incomingData.data[i];
981+
}
982+
if (configurationReceivedCallback != nullptr)
983+
{
984+
configurationReceivedCallback(CF_QR, 0, index);
985+
}
986+
987+
}
988+
break;
989+
case 0xBF:
990+
if (incomingData.data[3] == 0xFE)
991+
{
992+
touch.state = incomingData.data[5] == 1;
993+
touch.x = uint32_t(incomingData.data[6] << 8) | uint32_t(incomingData.data[7]);
994+
touch.y = uint32_t(incomingData.data[8] << 8) | uint32_t(incomingData.data[9]);
995+
}
996+
break;
930997
case 0xCA:
931998
if (incomingData.data[3] == 0xFE)
932999
{
@@ -942,22 +1009,66 @@ void ChronosESP32::dataReceived()
9421009
}
9431010
}
9441011
break;
1012+
case 0xEE:
1013+
if (incomingData.data[3] == 0xFE)
1014+
{
1015+
//nvIc
1016+
}
1017+
break;
1018+
case 0xEF:
1019+
if (incomingData.data[3] == 0xFE)
1020+
{
1021+
//nvData
1022+
}
1023+
break;
9451024
}
9461025
}
9471026
else if (incomingData.data[0] == 0xEA)
9481027
{
949-
if (incomingData.data[4] == 0x7E && incomingData.data[5] == 0x01)
1028+
if (incomingData.data[4] == 0x7E)
9501029
{
951-
String city = "";
952-
for (int c = 7; c < len; c++)
1030+
switch (incomingData.data[5])
9531031
{
954-
city += (char)incomingData.data[c];
1032+
case 0x01:
1033+
{
1034+
String city = "";
1035+
for (int c = 7; c < len; c++)
1036+
{
1037+
city += (char)incomingData.data[c];
1038+
}
1039+
weatherCity = city;
1040+
if (configurationReceivedCallback != nullptr)
1041+
{
1042+
configurationReceivedCallback(CF_WEATHER, 0, 1);
1043+
}
9551044
}
956-
weatherCity = city;
957-
if (configurationReceivedCallback != nullptr)
1045+
break;
1046+
case 0x02:
9581047
{
959-
configurationReceivedCallback(CF_WEATHER, 0, 1);
1048+
int size = incomingData.data[6];
1049+
int hour = incomingData.data[7];
1050+
for (int z = 0; z < size; z++)
1051+
{
1052+
if (hour + z >= FORECAST_SIZE)
1053+
{
1054+
break;
1055+
}
1056+
int icon = incomingData.data[8 + (6 * z)] >> 4;
1057+
int sign = (incomingData.data[8 + (6 * z)] & 1) ? -1 : 1;
1058+
int temp = ((int)incomingData.data[9 + (6 * z)]) * sign;
1059+
1060+
hourlyForecast[hour + z].day = this->getDayofYear();
1061+
hourlyForecast[hour + z].hour = hour + z;
1062+
hourlyForecast[hour + z].wind = (incomingData.data[10 + (6 * z)] * 256) + incomingData.data[11 + (6 * z)];
1063+
hourlyForecast[hour + z].humidity = incomingData.data[12 + (6 * z)];
1064+
hourlyForecast[hour + z].uv = incomingData.data[13 + (6 * z)];
1065+
hourlyForecast[hour + z].icon = icon;
1066+
hourlyForecast[hour + z].temp = temp;
1067+
}
1068+
}
1069+
break;
9601070
}
9611071
}
9621072
}
963-
}
1073+
}
1074+

0 commit comments

Comments
 (0)