Skip to content

Instantly share code, notes, and snippets.

@paulrouget
Last active May 8, 2023 14:03
Show Gist options
  • Save paulrouget/205163a6a922f8a933834a88f5e1514a to your computer and use it in GitHub Desktop.
Save paulrouget/205163a6a922f8a933834a88f5e1514a to your computer and use it in GitHub Desktop.
weather app
#include <k8mod_app.h>
#include <bitmaps.h>
#define FRAME_DURATION 500
#define FRAME_COUNT 2
const uint8_t DEGREE[] = {0x8e}; // Offset 28
const uint8_t RAIN[FRAME_COUNT][5] = {ICON_WEATHER_RAIN_0_V1, ICON_WEATHER_RAIN_1_V1};
const uint8_t CLOUDY[FRAME_COUNT][5] = {ICON_WEATHER_CLOUDY_0_V3, ICON_WEATHER_CLOUDY_1_V3};
const uint8_t SUNNY[FRAME_COUNT][5] = {ICON_WEATHER_SUNNY_0_V2, ICON_WEATHER_SUNNY_1_V2};
const uint8_t SUNNY_N_CLOUDY[FRAME_COUNT][5] = {ICON_WEATHER_SUNNY_N_CLOUDY_0_V3, ICON_WEATHER_SUNNY_N_CLOUDY_1_V3};
const uint8_t WINDY[FRAME_COUNT][5] = {ICON_WEATHER_WINDY_0_V1, ICON_WEATHER_WINDY_1_V1};
const uint8_t NONE[FRAME_COUNT][5] = {{0xF8, 0x23, 0x1A, 0xA8, 0x1F}, {0xF8, 0x00, 0x00, 0x00, 0x1F}};
const Format FMT_TITLE = {
.seg = Seg_S9,
.offset = 0,
.width = 7,
.fill_with = ' ',
.align = Alignment_Left,
};
const Format FMT_TEMP = {
.seg = Seg_S7,
.offset = 0,
.width = 3,
.fill_with = ' ',
.align = Alignment_Right,
};
static bool m_invalidated;
static int8_t m_temp;
static uint8_t *m_icon;
static uint16_t m_current_frame;
const char *init() {
m_invalidated = true;
m_temp = 0;
m_icon = (uint8_t *)NONE;
m_current_frame = 0;
return "CWeather";
}
uint16_t get_script_uuid() {
return 0x43A7;
}
void tick(const uint64_t *big_time) {
uint32_t time = (uint32_t)*big_time; // FIXME: can't do math operations on uint64_t. Otherwise: __aeabi_uldivmod undefined
uint16_t current = time % (FRAME_DURATION * FRAME_COUNT);
uint16_t frame_idx = current / FRAME_DURATION;
if (frame_idx != m_current_frame) {
m_current_frame = frame_idx;
m_invalidated = true;
}
if (m_invalidated) {
m_invalidated = false;
screen_clear();
screen_write_string_to_seg("WEATHER", &FMT_TITLE);
if (m_icon != (uint8_t *)NONE) {
screen_write_number_to_seg(m_temp, &FMT_TEMP);
screen_write_bytes_to_seg(Seg_S7, DEGREE, sizeof(DEGREE), 8, 21);
}
screen_write_to_matrix((const uint8_t(*)[5])(m_icon + m_current_frame * 5));
}
}
void on_bluetooth_receive(const uint8_t *data, uint32_t len) {
if (len != 2) {
print("Unexpected data. Probably a HTTP error");
} else {
print("Got data from phone");
m_temp = (int8_t)data[1];
m_invalidated = true;
int8_t wmo = (int8_t)data[0];
if (wmo <= 1) {
m_icon = (uint8_t *)SUNNY;
} else if (wmo <= 2) {
m_icon = (uint8_t *)SUNNY_N_CLOUDY;
} else if (wmo <= 3) {
m_icon = (uint8_t *)CLOUDY;
} else if (wmo < 95) {
m_icon = (uint8_t *)RAIN;
} else {
m_icon = (uint8_t *)WINDY;
}
}
}
void on_connection_changed(ConnectionStatus status) {
if (status == ConnectionStatus_ValidConnection) {
bluetooth_send(NULL, 0);
}
}
void invalidate() {
m_invalidated = true;
}
const app = {
uuid: 0x43A7,
on_data: (array) => {
const url = 'https://api.open-meteo.com/v1/forecast?latitude=25.04&longitude=121.52&current_weather=true';
fetch(url, data => {
const json = JSON.parse(data);
const resp = new Int8Array(2);
const wwo = json.current_weather.weathercode;
const temp = json.current_weather.temperature;
resp[0] = wwo;
resp[1] = temp;
send_bytes(resp);
}, error => { send_bytes(new Int8Array(0));});
}
};
app
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment