/* * fbdash.c * * Adapted by Florian Klemenz for use in the fb_dash project * * Source and all credit goes to * http://raspberrycompote.blogspot.com/ * -------------------------------------------------------------------------------------------- * * http://raspberrycompote.blogspot.ie/2014/03/low-level-graphics-on-raspberry-pi-part_14.html * * Original work by J-P Rosti (a.k.a -rst- and 'Raspberry Compote') * * Licensed under the Creative Commons Attribution 3.0 Unported License * (http://creativecommons.org/licenses/by/3.0/deed.en_US) * * Distributed in the hope that this will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #include #include #include #include #include #include #include "fblib.h" #define WIDTH 240 #define HEIGHT 320 char *fbp = 0; struct s_color { unsigned char r; unsigned char g; unsigned char b; }; typedef struct s_color color; struct s_sourcedata { char* text; char* temperature; char* humidity; }; typedef struct s_sourcedata sourcedata; void finish_with_error(MYSQL *con) { fprintf(stderr, "%s\n", mysql_error(con)); mysql_close(con); exit(1); } void updateSlot(char *fbp, sourcedata data, int x_offset, int y_offset, color c) { render_string(fbp, ubuntu_mono_24, data.text, x_offset, y_offset, c.r, c.g, c.b); render_string(fbp, ubuntu_mono_48, data.temperature, x_offset + 115, y_offset - 9, c.r, c.g, c.b); render_string(fbp, ubuntu_mono_48, "C", x_offset + 195, y_offset - 9, c.r, c.g, c.b); render_string(fbp, ubuntu_mono_48, data.humidity, x_offset + 115, y_offset + 26, c.r, c.g, c.b); render_string(fbp, ubuntu_mono_48, "%", x_offset + 195, y_offset + 26, c.r, c.g, c.b); } void updateData(char *fbp, int slot_height) { // query database for latest values printf("MySQL client version: %s\n", mysql_get_client_info()); MYSQL *con = mysql_init(NULL); if (con == NULL) { fprintf(stderr, "%s\n", mysql_error(con)); exit(1); } if (mysql_real_connect(con, "web-pi", "grafanaReader", "grafanaReader", "grafanaData", 0, NULL, 0) == NULL) { fprintf(stderr, "%s\n", mysql_error(con)); mysql_close(con); exit(1); } char* query = "\ SELECT \ time, \ source, \ metric, \ value \ FROM readings AS r \ INNER JOIN sources AS s ON r.source_id = s.id \ INNER JOIN metrics AS m ON r.metric_id = m.id \ WHERE \ time > (NOW() - 60 * 15) AND \ metric IN ('Luftfeuchte','Temperatur') AND \ source IN ('Esszimmer','Wohnzimmer', 'Schlafzimmer', 'Abstellkammer') \ ORDER BY time DESC \ LIMIT 100;"; //printf("%s\n",query); printf("Fetching data ...\n"); if (mysql_query(con, query)) { finish_with_error(con); } MYSQL_RES *result = mysql_store_result(con); if (result == NULL) { finish_with_error(con); } // define what to display sourcedata data[4] = { { "Esszimmer", NULL, NULL }, { "Wohnzimmer", NULL, NULL }, { "Schlafzimmer", NULL, NULL }, { "Abstellkammer", NULL, NULL } }; int num_fields = mysql_num_fields(result); if (num_fields > 3) { MYSQL_ROW row; while ((row = mysql_fetch_row(result))) { if (strlen(row[3]) > 4) row[3][4] = '\0'; // loose the secnod and third decimal ... // data binding for (int i = 0; i < 4; i++) { if (strcmp(row[1], data[i].text) == 0) { if (strcmp(row[2], "Temperatur") == 0 && data[i].temperature == NULL) data[i].temperature = row[3]; else if (strcmp(row[2], "Luftfeuchte") == 0 && data[i].humidity == NULL) data[i].humidity = row[3]; } } // debugging //for(int i = 0; i < num_fields; i++) printf("%s ", row[i] ? row[i] : "NULL"); //printf("\n"); } } printf("Updating dashboard...\n"); for (int i = 0; i < 4; i++) { color c = {255,125 + 25*i,25 + 25*i}; updateSlot(fbp, data[i], 15, 7 + slot_height * i, c); } printf("Done!\n"); mysql_free_result(result); mysql_close(con); } void draw() { clear_screen(fbp); // horizontal spacersint x_space = 10; int y_step_width = HEIGHT / 4; for (int i = 1; i < 4; i++) { int x0 = 15; int x1 = WIDTH - x0; int y = y_step_width * i; int r = 225; int g = 32; int b = 32; draw_line(fbp, x0, y-1, x1, y-1, r, g, b); draw_line(fbp, x0, y , x1, y , r, g, b); draw_line(fbp, x0, y+1, x1, y+1, r, g, b); } // fetch data from database and update screen updateData(fbp, y_step_width); } // application entry point int main(int argc, char* argv[]) { int fbfd = 0; long int screensize = 0; // Open the framebuffer file for reading and writing fbfd = open("/dev/fb1", O_RDWR); if (fbfd == -1) { printf("Error: cannot open framebuffer device.\n"); return(1); } printf("The framebuffer device was opened successfully.\n"); // map fb to user mem screensize = WIDTH*HEIGHT*2; fbp = (char*)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if ((int)fbp == -1) { printf("Failed to mmap.\n"); } else { // draw... draw(); } // cleanup //clear_screen(fbp); munmap(fbp, screensize); close(fbfd); return 0; }