├── .gitignore ├── .project ├── .pydevproject ├── .settings └── org.eclipse.core.resources.prefs ├── Button ├── Makefile ├── generate_uinput_names.sh ├── gpio-keys ├── gpio-keys.c └── uinput_names.inc ├── Clock ├── .gitignore ├── ApiKeys-example.py ├── Config-Example-Bedside.py ├── Config-Example-Berlin.py ├── Config-Example-London.py ├── Config-Example.py ├── GoogleMercatorProjection.py ├── PyQtPiClock.py ├── icons-darkblue │ ├── .gitignore │ ├── clear-day.png │ ├── clear-night.png │ ├── cloudy.png │ ├── fog.png │ ├── partly-cloudy-day.png │ ├── partly-cloudy-night.png │ ├── rain.png │ ├── sleet.png │ ├── snow.png │ ├── thunderstorm.png │ └── wind.png ├── icons-darkgreen │ ├── clear-day.png │ ├── clear-night.png │ ├── cloudy.png │ ├── fog.png │ ├── partly-cloudy-day.png │ ├── partly-cloudy-night.png │ ├── rain.png │ ├── sleet.png │ ├── snow.png │ ├── thunderstorm.png │ └── wind.png ├── icons-lightblue │ ├── .gitignore │ ├── clear-day.png │ ├── clear-night.png │ ├── cloudy.png │ ├── fog.png │ ├── partly-cloudy-day.png │ ├── partly-cloudy-night.png │ ├── rain.png │ ├── sleet.png │ ├── snow.png │ ├── thunderstorm.png │ └── wind.png ├── images │ ├── .gitignore │ ├── berlin-at-night-mrwallpaper.jpg │ ├── clockbackground-chris.png │ ├── clockbackground-jean.png │ ├── clockbackground-kelly.png │ ├── clockbackground-kevin.png │ ├── clockbackground.png │ ├── clockface3-darkblue.png │ ├── clockface3-darkgreen.png │ ├── clockface3.png │ ├── hourhand-darkblue.png │ ├── hourhand-darkgreen.png │ ├── hourhand.png │ ├── minhand-darkblue.png │ ├── minhand-darkgreen.png │ ├── minhand.png │ ├── sechand-darkblue.png │ ├── sechand-darkgreen.png │ ├── sechand.png │ ├── slideshow │ │ ├── daniel-h-tong-1310255-unsplash.jpg │ │ ├── johannes-plenio-629984-unsplash.jpg │ │ ├── nasa-53888-unsplash.jpg │ │ ├── patrick-tomasso-1311143-unsplash.jpg │ │ ├── roman-bozhko-251398-unsplash.jpg │ │ └── shot-by-cerqueira-1318576-unsplash.jpg │ ├── squares1-green.png │ ├── squares1-jean.png │ ├── squares1-kevin.png │ ├── squares2-green.png │ ├── squares2-jean.png │ └── squares2-kevin.png └── markers │ ├── Readme.md │ ├── markers.xcf │ ├── teardrop-dot.png │ ├── teardrop-family.png │ ├── teardrop-home.png │ ├── teardrop-school.png │ ├── teardrop-work.png │ └── teardrop.png ├── Contributed ├── PiClock_neo-aeon-Clockface-FliegerB.zip ├── PiClock_neo-aeon-ClockfaceGuide-GIMP.zip └── Readme.md ├── Documentation ├── 2015-06-11_10-36-44.png ├── Digital Clock v1.jpg ├── Digital Clock v2.jpg ├── Hardware.md ├── Hardware_Schematic.pdf ├── Hardware_Schematic.png ├── Hardware_Schematic.sch ├── Install-Clock-Only.md ├── Install-Jessie.md ├── Install.md ├── NeoPixel.jpg ├── Overview.md ├── ds18b20.jpg ├── gpiobuttons.jpg └── tsop4838.jpg ├── IR ├── IRCodes.pl └── lircd.conf ├── LICENSE ├── Leds └── NeoAmbi.py ├── PiClock.desktop ├── Pictures ├── 20141222_220127.jpg ├── 20141227_174953.jpg ├── 2015-05-10_17-01-52.png ├── 2015-05-16_17-36-06.png ├── 20150307_222711.jpg ├── 20150326_225245.jpg ├── 20150326_225305_Fotor_Collage.jpg ├── 20150404_165441_Fotor_Collage.jpg └── 20150412_182821a.jpg ├── README.md ├── Temperature ├── TempNames.py └── TempServer.py ├── gimp ├── Readme.md ├── clockbackground.xcf ├── clockbackground5.xcf ├── clockface3.xcf ├── hourhand.xcf ├── jeansxcf.xcf ├── minhand.xcf ├── sechand.xcf ├── squares2.xcf └── squres1.xcf ├── startup.sh ├── switcher.sh └── update.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # Configuration things to not commit API keys/location 6 | Clock/Api-Keys.py 7 | Clock/Config.py 8 | 9 | # From testing 10 | Clock/log.count 11 | Clock/*.log* 12 | 13 | # Distribution / packaging 14 | .Python 15 | env/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *,cover 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | 58 | # Sphinx documentation 59 | docs/_build/ 60 | 61 | # PyBuilder 62 | target/ 63 | 64 | Thumbs.db 65 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | PiClock 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /${PROJECT_DIR_NAME} 5 | /${PROJECT_DIR_NAME}/Clock 6 | 7 | python 2.7 8 | Default 9 | 10 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//Clock/Config-Example-Berlin.py=utf-8 3 | encoding//Clock/PyQtPiClock.py=utf-8 4 | -------------------------------------------------------------------------------- /Button/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS= -Wall -Werror -Wextra 2 | 3 | all: gpio-keys 4 | 5 | gpio-keys.o: gpio-keys.c uinput_names.inc 6 | 7 | uinput_names.inc: 8 | sh generate_uinput_names.sh >uinput_names.inc 9 | 10 | clean: 11 | rm gpio-keys gpio-keys.o uinput_names.inc 12 | -------------------------------------------------------------------------------- /Button/generate_uinput_names.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # taken from input_map.sh from lircd distribution 3 | # http://www.lirc.org/ 4 | 5 | TYPES="KEY BTN" 6 | file=${1:-/usr/include/linux/input.h} 7 | 8 | # Use gnu-sed on Macosx 9 | if test "`uname`" = 'Darwin'; then 10 | SED=gsed 11 | else 12 | SED=sed 13 | fi 14 | 15 | for type in $TYPES; do 16 | grep "^#define ${type}_" < $file|sort|$SED -n --expression="s/^#define \([^ \t]*\)[ \t][ \t]*\([0-9][0-9a-fA-FxX]*\).*/{\"\1\", \2},/p" 17 | done 18 | -------------------------------------------------------------------------------- /Button/gpio-keys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Button/gpio-keys -------------------------------------------------------------------------------- /Button/gpio-keys.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 Kevin Uhlir 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | 25 | Portions taken from input_map.sh from lircd distribution http://www.lirc.org/ 26 | Copyright (C) 2008 Christoph Bartelmus (MIT License) 27 | 28 | Portions taken from RPi-GPIO https://pypi.python.org/pypi/RPi.GPIO 29 | Copyright (c) 2012-2015 Ben Croston (MIT License) 30 | 31 | 32 | 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | int debug = 0; 51 | 52 | typedef struct { 53 | int pin; 54 | int key; 55 | int last; 56 | int fd; 57 | } pin_t; 58 | 59 | struct uinput_key { 60 | char *name; 61 | unsigned short code; 62 | 63 | } uinput_keys[] = { 64 | #include "uinput_names.inc" 65 | { 66 | NULL, 0} 67 | }; 68 | 69 | #define MAX_KEYS 50 70 | static pin_t keys[MAX_KEYS]; 71 | struct pollfd pollfds[MAX_KEYS]; 72 | int pollfd_count = 0; 73 | 74 | int ufd = -1; 75 | static char *config_file = NULL; 76 | static char *device_name = NULL; 77 | 78 | 79 | int keycode(char *name) 80 | { 81 | if (isdigit(name[0])) 82 | { 83 | int code = strtol(name,NULL,0); 84 | if (code == 0) return(-1); 85 | return(code); 86 | } 87 | struct uinput_key *i; 88 | for (i = uinput_keys; i->name; i++) 89 | { 90 | if (strcmp(name,i->name) == 0) 91 | { 92 | return(i->code); 93 | } 94 | } 95 | return(-1); 96 | } 97 | 98 | static char keynametmp[50]; 99 | char * keyname(int code) 100 | { 101 | struct uinput_key *i; 102 | for (i = uinput_keys; i->name; i++) 103 | { 104 | if (i->code == code) 105 | { 106 | return(i->name); 107 | } 108 | } 109 | sprintf(keynametmp,"unknown(0x%x)",code); 110 | return(keynametmp); 111 | } 112 | 113 | static int read_value (int fd) 114 | { 115 | char v; 116 | 117 | if (lseek (fd, 0, SEEK_SET) < 0) { 118 | perror ("lseek"); 119 | exit (0); 120 | } 121 | if (read (fd, &v, 1) != 1) { 122 | perror ("read"); 123 | exit (0); 124 | } 125 | return v == '0' ? 0 : 1; 126 | } 127 | 128 | 129 | #define BCM2708_PERI_BASE_DEFAULT 0x20000000 130 | #define GPIO_BASE_OFFSET 0x200000 131 | #define FSEL_OFFSET 0 // 0x0000 132 | #define SET_OFFSET 7 // 0x001c / 4 133 | #define CLR_OFFSET 10 // 0x0028 / 4 134 | #define PINLEVEL_OFFSET 13 // 0x0034 / 4 135 | #define EVENT_DETECT_OFFSET 16 // 0x0040 / 4 136 | #define RISING_ED_OFFSET 19 // 0x004c / 4 137 | #define FALLING_ED_OFFSET 22 // 0x0058 / 4 138 | #define HIGH_DETECT_OFFSET 25 // 0x0064 / 4 139 | #define LOW_DETECT_OFFSET 28 // 0x0070 / 4 140 | #define PULLUPDN_OFFSET 37 // 0x0094 / 4 141 | #define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4 142 | 143 | #define PAGE_SIZE (4*1024) 144 | #define BLOCK_SIZE (4*1024) 145 | 146 | 147 | #define PUD_OFF 0 148 | #define PUD_DOWN 1 149 | #define PUD_UP 2 150 | 151 | 152 | static volatile uint32_t *gpio_map; 153 | 154 | void short_wait(void) 155 | { 156 | int i; 157 | 158 | for (i=0; i<150; i++) { // wait 150 cycles 159 | asm volatile("nop"); 160 | } 161 | } 162 | 163 | void gpio_setup(void) 164 | { 165 | int mem_fd; 166 | uint8_t *gpio_mem; 167 | uint32_t peri_base = BCM2708_PERI_BASE_DEFAULT; 168 | uint32_t gpio_base; 169 | unsigned char buf[4]; 170 | FILE *fp; 171 | 172 | // get peri base from device tree 173 | if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) { 174 | fseek(fp, 4, SEEK_SET); 175 | if (fread(buf, 1, sizeof buf, fp) == sizeof buf) { 176 | peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0; 177 | } 178 | fclose(fp); 179 | } 180 | 181 | gpio_base = peri_base + GPIO_BASE_OFFSET; 182 | 183 | // mmap the GPIO memory registers 184 | if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { 185 | perror ("/dev/mem"); 186 | exit (1); 187 | } 188 | 189 | if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { 190 | perror ("gpio malloc"); 191 | exit (1); 192 | } 193 | 194 | if ((uint32_t)gpio_mem % PAGE_SIZE) 195 | gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE); 196 | 197 | gpio_map = (uint32_t *)mmap( (caddr_t)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base); 198 | 199 | if ((void *)gpio_map == MAP_FAILED) { 200 | perror ("gpio memmap"); 201 | exit (1); 202 | } 203 | 204 | } 205 | 206 | void set_pullupdn(int gpio, int pud) 207 | { 208 | int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32); 209 | int shift = (gpio%32); 210 | 211 | if (pud == PUD_DOWN) 212 | *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN; 213 | else if (pud == PUD_UP) 214 | *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP; 215 | else // pud == PUD_OFF 216 | *(gpio_map+PULLUPDN_OFFSET) &= ~3; 217 | 218 | short_wait(); 219 | *(gpio_map+clk_offset) = 1 << shift; 220 | short_wait(); 221 | *(gpio_map+PULLUPDN_OFFSET) &= ~3; 222 | *(gpio_map+clk_offset) = 0; 223 | } 224 | 225 | void gpio_cleanup(void) 226 | { 227 | munmap((caddr_t)gpio_map, BLOCK_SIZE); 228 | } 229 | 230 | void uinput_setup() 231 | { 232 | pin_t *k; 233 | ufd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); 234 | if (ufd < 0) { 235 | perror ("open error: /dev/uinput"); 236 | exit (1); 237 | } 238 | 239 | if (ioctl (ufd, UI_SET_EVBIT, EV_KEY) < 0 240 | || ioctl (ufd, UI_SET_EVBIT, EV_REL) < 0) { 241 | perror ("ioctl UI_SET_EVBIT"); 242 | exit (1); 243 | } 244 | if (debug > 1) fprintf(stderr,"opened uinput\n"); 245 | 246 | struct uinput_user_dev uinp; 247 | snprintf (uinp.name, sizeof (uinp.name), device_name ? device_name : "gpio button device"); 248 | uinp.id.version = 4; /* lies, lies, lies */ 249 | uinp.id.bustype = BUS_USB; 250 | uinp.id.product = 1; 251 | uinp.id.vendor = 1; 252 | 253 | if (write (ufd, &uinp, sizeof (uinp)) != sizeof (uinp)) { 254 | perror ("write error initializing: /dev/uinput"); 255 | exit (1); 256 | } 257 | 258 | if (debug > 0) fprintf(stderr,"setup uinput device %s\n",uinp.name); 259 | 260 | for (k = keys; k->key; k++) 261 | { 262 | if (ioctl (ufd, UI_SET_KEYBIT, k->key) < 0) { 263 | perror ("ioctl UI_SET_KEYBIT"); 264 | exit (1); 265 | } 266 | 267 | if (debug > 0) fprintf(stderr,"uinput keycode set 0x%x %s for gpio pin %d\n", 268 | k->key,keyname(k->key),k->pin); 269 | 270 | } 271 | if (ioctl(ufd, UI_DEV_CREATE) < 0) { 272 | perror ("ioctl UI_DEV_CREATE"); 273 | exit (1); 274 | } 275 | 276 | if (debug > 0) fprintf(stderr,"uinput device created\n"); 277 | } 278 | 279 | 280 | void pollfd_setup() 281 | { 282 | pin_t *k; 283 | pollfd_count = 0; 284 | for (k = keys; k->key; k++) 285 | { 286 | pollfd_count++; 287 | } 288 | 289 | struct pollfd *p = pollfds; 290 | for (k = keys; k->key; k++, p++) 291 | { 292 | p->fd = k->fd; 293 | p->events = POLLPRI; 294 | p->revents = 0; 295 | } 296 | 297 | 298 | 299 | } 300 | 301 | void gpio_sys_setup() 302 | { 303 | char path[300]; 304 | char epath[300]; 305 | char num[20]; 306 | FILE *efp; 307 | FILE *fp; 308 | pin_t *k; 309 | snprintf (epath, sizeof (epath), "/sys/class/gpio/export"); 310 | efp = fopen (epath, "w"); 311 | if (!efp) { 312 | fprintf(stderr,"open error:"); 313 | perror (epath); 314 | exit (1); 315 | } 316 | for (k = keys; k->key; k++) 317 | { 318 | 319 | // see if the pin is exported 320 | snprintf (path, sizeof (path), "/sys/class/gpio/gpio%d/value", k->pin); 321 | int fd = open (path, O_RDONLY); 322 | if (fd < 0) // not exported 323 | { 324 | 325 | // export the pin 326 | snprintf (num, sizeof (num), "%d", k->pin); 327 | if (fputs (num, efp) < 0) { 328 | fprintf(stderr,"write error:"); 329 | perror (epath); 330 | exit (1); 331 | } 332 | if (fflush (efp) < 0) { 333 | fprintf(stderr,"flush error:"); 334 | perror (epath); 335 | exit (1); 336 | } 337 | if (debug > 1) fprintf(stderr,"exported gpio %d\n",k->pin); 338 | } 339 | else 340 | { 341 | if (debug > 1) fprintf(stderr,"gpio %d already exported\n",k->pin); 342 | close(fd); 343 | } 344 | } 345 | 346 | usleep(100000); 347 | 348 | for (k = keys; k->key; k++) 349 | { 350 | 351 | set_pullupdn(k->pin, PUD_UP); 352 | 353 | if (debug > 1) fprintf(stderr,"gpio %d pullup set\n",k->pin); 354 | 355 | // set direction input 356 | snprintf (path, sizeof (path), "/sys/class/gpio/gpio%d/direction", k->pin); 357 | fp = fopen (path, "w"); 358 | if (!fp) { 359 | fprintf(stderr,"open error:"); 360 | perror (path); 361 | exit (1); 362 | } 363 | if (fputs ("in", fp) < 0) { 364 | fprintf(stderr,"write error:"); 365 | perror (path); 366 | exit (1); 367 | } 368 | if (fclose (fp) != 0) { 369 | fprintf(stderr,"close error:"); 370 | perror (path); 371 | exit (1); 372 | } 373 | 374 | 375 | // set edge interrupt 376 | snprintf (path, sizeof (path), "/sys/class/gpio/gpio%d/edge", k->pin); 377 | fp = fopen (path, "w"); 378 | if (!fp) { 379 | fprintf(stderr,"open error:"); 380 | perror (path); 381 | exit (1); 382 | } 383 | if (fputs ("both", fp) < 0) { 384 | fprintf(stderr,"write error:"); 385 | perror (path); 386 | exit (1); 387 | } 388 | if (fclose (fp) != 0) { 389 | fprintf(stderr,"close error:"); 390 | perror (path); 391 | exit (1); 392 | } 393 | 394 | if (debug > 1) fprintf(stderr,"gpio %d edge interupt set\n",k->pin); 395 | // open value file 396 | 397 | 398 | snprintf (path, sizeof (path), "/sys/class/gpio/gpio%d/value", k->pin); 399 | int fd = open (path, O_RDONLY); 400 | if (fd < 0) { 401 | fprintf(stderr,"open error:"); 402 | perror (path); 403 | exit (1); 404 | } 405 | 406 | 407 | k->fd = fd; 408 | k->last = read_value (k->fd); 409 | 410 | } 411 | 412 | fclose (efp); 413 | } 414 | 415 | static void init(void) 416 | { 417 | 418 | gpio_setup(); 419 | 420 | gpio_sys_setup(); 421 | 422 | uinput_setup(); 423 | 424 | pollfd_setup(); 425 | 426 | } 427 | 428 | 429 | 430 | static void sendkey(int code, int val) 431 | { 432 | struct input_event ev; 433 | 434 | memset (&ev, 0, sizeof (ev)); 435 | ev.type = EV_KEY; 436 | ev.code = code; 437 | ev.value = val; 438 | 439 | if (write (ufd, &ev, sizeof (ev)) != sizeof (ev)) { 440 | perror ("write key_event"); 441 | exit (1); 442 | } 443 | 444 | ev.type = EV_SYN; 445 | ev.code = SYN_REPORT; 446 | ev.value = 0; 447 | 448 | if (write (ufd, &ev, sizeof (ev)) != sizeof (ev)) { 449 | perror ("write syn_event"); 450 | exit (1); 451 | } 452 | 453 | if (debug > 0) fprintf(stderr,"key sent 0x%x %s %s\n",code,keyname(code),val?"pressed":"released"); 454 | 455 | } 456 | 457 | static void one_event(void ) 458 | { 459 | 460 | if (poll (pollfds, pollfd_count, -1) < 0) { 461 | perror ("poll"); 462 | exit (1); 463 | } 464 | 465 | 466 | struct pollfd *p; 467 | pin_t *k; 468 | int pc; 469 | for (k = keys, p = pollfds, pc = pollfd_count; pc > 0; p++, k++, pc--) 470 | { 471 | if (p->revents & POLLPRI) 472 | { 473 | usleep(20000); // 20ms debounce 474 | int v = read_value(k->fd); 475 | if (k->last != v) 476 | { 477 | if (debug > 0) fprintf(stderr,"gpio button change %d value %d\n",k->pin,v); 478 | sendkey(k->key,v ^ 1); 479 | } 480 | k->last = v; 481 | } 482 | p->revents = 0; 483 | p->events = POLLPRI; 484 | } 485 | 486 | } 487 | 488 | 489 | void sighandler(int s) 490 | { 491 | (void)s; 492 | if (debug > 0) fprintf(stderr,"shutting down\n"); 493 | if (ufd > -1) ioctl (ufd, UI_DEV_DESTROY ); 494 | if (debug > 0) fprintf(stderr,"uinput device destroyed\n"); 495 | char epath[300]; 496 | snprintf (epath, sizeof (epath), "/sys/class/gpio/unexport"); 497 | FILE *efp = fopen (epath, "w"); 498 | if (!efp) { 499 | fprintf(stderr,"open error:"); 500 | perror (epath); 501 | exit (1); 502 | } 503 | pin_t *k; 504 | for (k = keys; k->key; k++) 505 | { 506 | close(k->fd); 507 | char num[10]; 508 | snprintf (num, sizeof (num), "%d", k->pin); 509 | if (fputs (num, efp) < 0) { 510 | fprintf(stderr,"write error:"); 511 | perror (epath); 512 | exit (1); 513 | } 514 | if (fflush (efp) < 0) { 515 | fprintf(stderr,"flush error:"); 516 | perror (epath); 517 | exit (1); 518 | } 519 | if (debug > 0) fprintf(stderr,"unexported %d\n",k->pin); 520 | set_pullupdn(k->pin, PUD_OFF); 521 | if (debug > 1) fprintf(stderr,"pullup turned off %d\n",k->pin); 522 | } 523 | fclose(efp); 524 | if (debug > 0) fprintf(stderr,"shutdown complete\n"); 525 | exit(0); 526 | } 527 | 528 | void usage(void) 529 | { 530 | fprintf(stderr,"\ngpio-keys: [options] gpio:keyname, ...\n" 531 | " -h --help this message\n" 532 | " -c --config-file specify a config file\n" 533 | " -n --device-name specify the device name for creating the uinput device\n" 534 | " gpio:keyname for specifying the gpio pin which will be mapped to a keyname\n" 535 | "\n" 536 | " Multiple gpio:keyname can be specified\n" 537 | "\n" 538 | " A config file consists of lines with gpio and keyname pairs, one per line\n" 539 | " lines starting with # are taken as comment lines\n" 540 | "\n" 541 | " gpio-keys requires root privileges (because it uses uinput)\n" 542 | ); 543 | 544 | } 545 | 546 | int main(int argc, char **argv) 547 | { 548 | 549 | int c; 550 | pin_t *kp = keys; 551 | pin_t *kp2; 552 | char *colon; 553 | 554 | memset(keys,0,sizeof(keys)); 555 | while (1) { 556 | int option_index = 0; 557 | static struct option long_options[] = { 558 | {"config-file", required_argument, 0, 'c' }, 559 | {"device-name", required_argument, 0, 'n' }, 560 | {"help", no_argument, 0, 'h' }, 561 | {"debug", no_argument, 0, 'd' }, 562 | {0, 0, 0, 0 } 563 | }; 564 | 565 | c = getopt_long(argc, argv, "c:n:k:dh", 566 | long_options, &option_index); 567 | if (c == -1) 568 | break; 569 | 570 | switch (c) { 571 | case 'c': 572 | config_file = strdup(optarg); 573 | break; 574 | case 'n': 575 | device_name = strdup(optarg); 576 | break; 577 | case 'h': 578 | usage(); 579 | exit(0); 580 | break; 581 | case 'd': 582 | debug++; 583 | break; 584 | 585 | case '?': 586 | default: 587 | fprintf(stderr,"Unknown option: %c\n",c); 588 | usage(); 589 | exit(1); 590 | } 591 | } 592 | 593 | if (optind < argc) { 594 | while (optind < argc) { 595 | optarg = argv[optind++]; 596 | colon = strchr(optarg,':'); 597 | if (!colon) 598 | { 599 | fprintf(stderr,"Unknown key syntax: %s\n",optarg); 600 | usage(); 601 | exit(1); 602 | } 603 | colon++; 604 | int pin = atoi(optarg); 605 | int key = keycode(colon); 606 | if (key < 0) 607 | { 608 | fprintf(stderr,"Unknown key code: %s\n",colon); 609 | usage(); 610 | exit(1); 611 | } 612 | for (kp2 = keys; kp2->key; kp2++) 613 | { 614 | if (kp2->pin == pin) 615 | { 616 | fprintf(stderr,"gpio pin %d already set as keycode 0x%x %s for command line argument: %s\n", 617 | pin, kp2->key, keyname(kp2->key), optarg); 618 | usage(); 619 | exit(1); 620 | } 621 | } 622 | if (debug > 0) fprintf(stderr,"adding gpio pin %d as keycode 0x%x %s\n", 623 | pin,key, keyname(key)); 624 | kp->pin = pin; 625 | kp->key = key; 626 | kp++; 627 | if ((kp - keys) >= MAX_KEYS) 628 | { 629 | fprintf(stderr, " too many keys specfied. %d max.\n",MAX_KEYS); 630 | usage(); 631 | exit(1); 632 | } 633 | } 634 | } 635 | 636 | if (config_file) 637 | { 638 | FILE *fp; 639 | if ((fp = fopen(config_file, "r")) != NULL) { 640 | int pin; 641 | char name[51]; 642 | char line[255]; 643 | while(fgets(line,250,fp) != NULL) 644 | { 645 | if (line[0] == '#') continue; 646 | if (sscanf(line,"%d%50s",&pin,name) == 2) 647 | { 648 | int key = keycode(name); 649 | if (key < 0) 650 | { 651 | fprintf(stderr,"Unknown key code while reading %s: %s\n",config_file,name); 652 | usage(); 653 | exit(1); 654 | } 655 | for (kp2 = keys; kp2->key; kp2++) 656 | { 657 | if (kp2->pin == pin) 658 | { 659 | fprintf(stderr,"gpio pin %d already set as keycode 0x%x %s for config line: %s\n", 660 | pin, kp2->key, keyname(kp2->key),line); 661 | usage(); 662 | exit(1); 663 | } 664 | } 665 | if (debug > 0) fprintf(stderr,"adding gpio pin %d as keycode 0x%x %s\n", 666 | pin,key, keyname(key)); 667 | kp->pin = pin; 668 | kp->key = key; 669 | kp++; 670 | if ((kp - keys) >= MAX_KEYS) 671 | { 672 | fprintf(stderr, " too many keys specfied. %d max.\n",MAX_KEYS); 673 | usage(); 674 | exit(1); 675 | } 676 | } 677 | } 678 | fclose(fp); 679 | } 680 | else 681 | { 682 | fprintf(stderr,"can't open config file: %s\n",config_file); 683 | usage(); 684 | exit(1); 685 | } 686 | } 687 | 688 | if (keys[0].key == 0) 689 | { 690 | fprintf(stderr,"No gpio keys specified... nothing to do... quitting.\n"); 691 | usage(); 692 | exit(1); 693 | } 694 | init(); 695 | signal(SIGINT, sighandler); 696 | signal(SIGTERM, sighandler); 697 | 698 | for(;;) 699 | { 700 | one_event(); 701 | } 702 | 703 | return(0); 704 | } 705 | 706 | -------------------------------------------------------------------------------- /Button/uinput_names.inc: -------------------------------------------------------------------------------- 1 | {"KEY_0", 11}, 2 | {"KEY_1", 2}, 3 | {"KEY_102ND", 86}, 4 | {"KEY_10CHANNELSDOWN", 0x1b9}, 5 | {"KEY_10CHANNELSUP", 0x1b8}, 6 | {"KEY_2", 3}, 7 | {"KEY_3", 4}, 8 | {"KEY_4", 5}, 9 | {"KEY_5", 6}, 10 | {"KEY_6", 7}, 11 | {"KEY_7", 8}, 12 | {"KEY_8", 9}, 13 | {"KEY_9", 10}, 14 | {"KEY_A", 30}, 15 | {"KEY_AB", 0x196}, 16 | {"KEY_ADDRESSBOOK", 0x1ad}, 17 | {"KEY_AGAIN", 129}, 18 | {"KEY_ALTERASE", 222}, 19 | {"KEY_ANGLE", 0x173}, 20 | {"KEY_APOSTROPHE", 40}, 21 | {"KEY_ARCHIVE", 0x169}, 22 | {"KEY_AUDIO", 0x188}, 23 | {"KEY_AUX", 0x186}, 24 | {"KEY_B", 48}, 25 | {"KEY_BACK", 158}, 26 | {"KEY_BACKSLASH", 43}, 27 | {"KEY_BACKSPACE", 14}, 28 | {"KEY_BASSBOOST", 209}, 29 | {"KEY_BATTERY", 236}, 30 | {"KEY_BLUE", 0x191}, 31 | {"KEY_BLUETOOTH", 237}, 32 | {"KEY_BOOKMARKS", 156}, 33 | {"KEY_BREAK", 0x19b}, 34 | {"KEY_BRIGHTNESSDOWN", 224}, 35 | {"KEY_BRIGHTNESSUP", 225}, 36 | {"KEY_BRIGHTNESS_CYCLE", 243}, 37 | {"KEY_BRIGHTNESS_ZERO", 244}, 38 | {"KEY_BRL_DOT1", 0x1f1}, 39 | {"KEY_BRL_DOT10", 0x1fa}, 40 | {"KEY_BRL_DOT2", 0x1f2}, 41 | {"KEY_BRL_DOT3", 0x1f3}, 42 | {"KEY_BRL_DOT4", 0x1f4}, 43 | {"KEY_BRL_DOT5", 0x1f5}, 44 | {"KEY_BRL_DOT6", 0x1f6}, 45 | {"KEY_BRL_DOT7", 0x1f7}, 46 | {"KEY_BRL_DOT8", 0x1f8}, 47 | {"KEY_BRL_DOT9", 0x1f9}, 48 | {"KEY_C", 46}, 49 | {"KEY_CALC", 140}, 50 | {"KEY_CALENDAR", 0x18d}, 51 | {"KEY_CAMERA", 212}, 52 | {"KEY_CAMERA_DOWN", 0x218}, 53 | {"KEY_CAMERA_FOCUS", 0x210}, 54 | {"KEY_CAMERA_LEFT", 0x219}, 55 | {"KEY_CAMERA_RIGHT", 0x21a}, 56 | {"KEY_CAMERA_UP", 0x217}, 57 | {"KEY_CAMERA_ZOOMIN", 0x215}, 58 | {"KEY_CAMERA_ZOOMOUT", 0x216}, 59 | {"KEY_CANCEL", 223}, 60 | {"KEY_CAPSLOCK", 58}, 61 | {"KEY_CD", 0x17f}, 62 | {"KEY_CHANNEL", 0x16b}, 63 | {"KEY_CHANNELDOWN", 0x193}, 64 | {"KEY_CHANNELUP", 0x192}, 65 | {"KEY_CHAT", 216}, 66 | {"KEY_CLEAR", 0x163}, 67 | {"KEY_CLOSE", 206}, 68 | {"KEY_CLOSECD", 160}, 69 | {"KEY_COFFEE", 152}, 70 | {"KEY_COMMA", 51}, 71 | {"KEY_COMPOSE", 127}, 72 | {"KEY_COMPUTER", 157}, 73 | {"KEY_CONFIG", 171}, 74 | {"KEY_CONNECT", 218}, 75 | {"KEY_CONTEXT_MENU", 0x1b6}, 76 | {"KEY_COPY", 133}, 77 | {"KEY_CUT", 137}, 78 | {"KEY_CYCLEWINDOWS", 154}, 79 | {"KEY_D", 32}, 80 | {"KEY_DASHBOARD", 204}, 81 | {"KEY_DATABASE", 0x1aa}, 82 | {"KEY_DELETE", 111}, 83 | {"KEY_DELETEFILE", 146}, 84 | {"KEY_DEL_EOL", 0x1c0}, 85 | {"KEY_DEL_EOS", 0x1c1}, 86 | {"KEY_DEL_LINE", 0x1c3}, 87 | {"KEY_DIGITS", 0x19d}, 88 | {"KEY_DIRECTION", 153}, 89 | {"KEY_DIRECTORY", 0x18a}, 90 | {"KEY_DISPLAYTOGGLE", 0x1af}, 91 | {"KEY_DISPLAY_OFF", 245}, 92 | {"KEY_DOCUMENTS", 235}, 93 | {"KEY_DOLLAR", 0x1b2}, 94 | {"KEY_DOT", 52}, 95 | {"KEY_DOWN", 108}, 96 | {"KEY_DVD", 0x185}, 97 | {"KEY_E", 18}, 98 | {"KEY_EDIT", 176}, 99 | {"KEY_EDITOR", 0x1a6}, 100 | {"KEY_EJECTCD", 161}, 101 | {"KEY_EJECTCLOSECD", 162}, 102 | {"KEY_EMAIL", 215}, 103 | {"KEY_END", 107}, 104 | {"KEY_ENTER", 28}, 105 | {"KEY_EPG", 0x16d}, 106 | {"KEY_EQUAL", 13}, 107 | {"KEY_ESC", 1}, 108 | {"KEY_EURO", 0x1b3}, 109 | {"KEY_EXIT", 174}, 110 | {"KEY_F", 33}, 111 | {"KEY_F1", 59}, 112 | {"KEY_F10", 68}, 113 | {"KEY_F11", 87}, 114 | {"KEY_F12", 88}, 115 | {"KEY_F13", 183}, 116 | {"KEY_F14", 184}, 117 | {"KEY_F15", 185}, 118 | {"KEY_F16", 186}, 119 | {"KEY_F17", 187}, 120 | {"KEY_F18", 188}, 121 | {"KEY_F19", 189}, 122 | {"KEY_F2", 60}, 123 | {"KEY_F20", 190}, 124 | {"KEY_F21", 191}, 125 | {"KEY_F22", 192}, 126 | {"KEY_F23", 193}, 127 | {"KEY_F24", 194}, 128 | {"KEY_F3", 61}, 129 | {"KEY_F4", 62}, 130 | {"KEY_F5", 63}, 131 | {"KEY_F6", 64}, 132 | {"KEY_F7", 65}, 133 | {"KEY_F8", 66}, 134 | {"KEY_F9", 67}, 135 | {"KEY_FASTFORWARD", 208}, 136 | {"KEY_FAVORITES", 0x16c}, 137 | {"KEY_FILE", 144}, 138 | {"KEY_FINANCE", 219}, 139 | {"KEY_FIND", 136}, 140 | {"KEY_FIRST", 0x194}, 141 | {"KEY_FN", 0x1d0}, 142 | {"KEY_FN_1", 0x1de}, 143 | {"KEY_FN_2", 0x1df}, 144 | {"KEY_FN_B", 0x1e4}, 145 | {"KEY_FN_D", 0x1e0}, 146 | {"KEY_FN_E", 0x1e1}, 147 | {"KEY_FN_ESC", 0x1d1}, 148 | {"KEY_FN_F", 0x1e2}, 149 | {"KEY_FN_F1", 0x1d2}, 150 | {"KEY_FN_F10", 0x1db}, 151 | {"KEY_FN_F11", 0x1dc}, 152 | {"KEY_FN_F12", 0x1dd}, 153 | {"KEY_FN_F2", 0x1d3}, 154 | {"KEY_FN_F3", 0x1d4}, 155 | {"KEY_FN_F4", 0x1d5}, 156 | {"KEY_FN_F5", 0x1d6}, 157 | {"KEY_FN_F6", 0x1d7}, 158 | {"KEY_FN_F7", 0x1d8}, 159 | {"KEY_FN_F8", 0x1d9}, 160 | {"KEY_FN_F9", 0x1da}, 161 | {"KEY_FN_S", 0x1e3}, 162 | {"KEY_FORWARD", 159}, 163 | {"KEY_FORWARDMAIL", 233}, 164 | {"KEY_FRAMEBACK", 0x1b4}, 165 | {"KEY_FRAMEFORWARD", 0x1b5}, 166 | {"KEY_FRONT", 132}, 167 | {"KEY_G", 34}, 168 | {"KEY_GAMES", 0x1a1}, 169 | {"KEY_GOTO", 0x162}, 170 | {"KEY_GRAPHICSEDITOR", 0x1a8}, 171 | {"KEY_GRAVE", 41}, 172 | {"KEY_GREEN", 0x18f}, 173 | {"KEY_H", 35}, 174 | {"KEY_HANGEUL", 122}, 175 | {"KEY_HANJA", 123}, 176 | {"KEY_HELP", 138}, 177 | {"KEY_HENKAN", 92}, 178 | {"KEY_HIRAGANA", 91}, 179 | {"KEY_HOME", 102}, 180 | {"KEY_HOMEPAGE", 172}, 181 | {"KEY_HP", 211}, 182 | {"KEY_I", 23}, 183 | {"KEY_IMAGES", 0x1ba}, 184 | {"KEY_INFO", 0x166}, 185 | {"KEY_INSERT", 110}, 186 | {"KEY_INS_LINE", 0x1c2}, 187 | {"KEY_ISO", 170}, 188 | {"KEY_J", 36}, 189 | {"KEY_K", 37}, 190 | {"KEY_KATAKANA", 90}, 191 | {"KEY_KATAKANAHIRAGANA", 93}, 192 | {"KEY_KBDILLUMDOWN", 229}, 193 | {"KEY_KBDILLUMTOGGLE", 228}, 194 | {"KEY_KBDILLUMUP", 230}, 195 | {"KEY_KEYBOARD", 0x176}, 196 | {"KEY_KP0", 82}, 197 | {"KEY_KP1", 79}, 198 | {"KEY_KP2", 80}, 199 | {"KEY_KP3", 81}, 200 | {"KEY_KP4", 75}, 201 | {"KEY_KP5", 76}, 202 | {"KEY_KP6", 77}, 203 | {"KEY_KP7", 71}, 204 | {"KEY_KP8", 72}, 205 | {"KEY_KP9", 73}, 206 | {"KEY_KPASTERISK", 55}, 207 | {"KEY_KPCOMMA", 121}, 208 | {"KEY_KPDOT", 83}, 209 | {"KEY_KPENTER", 96}, 210 | {"KEY_KPEQUAL", 117}, 211 | {"KEY_KPJPCOMMA", 95}, 212 | {"KEY_KPLEFTPAREN", 179}, 213 | {"KEY_KPMINUS", 74}, 214 | {"KEY_KPPLUS", 78}, 215 | {"KEY_KPPLUSMINUS", 118}, 216 | {"KEY_KPRIGHTPAREN", 180}, 217 | {"KEY_KPSLASH", 98}, 218 | {"KEY_L", 38}, 219 | {"KEY_LANGUAGE", 0x170}, 220 | {"KEY_LAST", 0x195}, 221 | {"KEY_LEFT", 105}, 222 | {"KEY_LEFTALT", 56}, 223 | {"KEY_LEFTBRACE", 26}, 224 | {"KEY_LEFTCTRL", 29}, 225 | {"KEY_LEFTMETA", 125}, 226 | {"KEY_LEFTSHIFT", 42}, 227 | {"KEY_LINEFEED", 101}, 228 | {"KEY_LIST", 0x18b}, 229 | {"KEY_LOGOFF", 0x1b1}, 230 | {"KEY_M", 50}, 231 | {"KEY_MACRO", 112}, 232 | {"KEY_MAIL", 155}, 233 | {"KEY_MAX", 0x2ff}, 234 | {"KEY_MEDIA", 226}, 235 | {"KEY_MEDIA_REPEAT", 0x1b7}, 236 | {"KEY_MEMO", 0x18c}, 237 | {"KEY_MENU", 139}, 238 | {"KEY_MESSENGER", 0x1ae}, 239 | {"KEY_MHP", 0x16f}, 240 | {"KEY_MICMUTE", 248}, 241 | {"KEY_MINUS", 12}, 242 | {"KEY_MODE", 0x175}, 243 | {"KEY_MOVE", 175}, 244 | {"KEY_MP3", 0x187}, 245 | {"KEY_MSDOS", 151}, 246 | {"KEY_MUHENKAN", 94}, 247 | {"KEY_MUTE", 113}, 248 | {"KEY_N", 49}, 249 | {"KEY_NEW", 181}, 250 | {"KEY_NEWS", 0x1ab}, 251 | {"KEY_NEXT", 0x197}, 252 | {"KEY_NEXTSONG", 163}, 253 | {"KEY_NUMERIC_0", 0x200}, 254 | {"KEY_NUMERIC_1", 0x201}, 255 | {"KEY_NUMERIC_2", 0x202}, 256 | {"KEY_NUMERIC_3", 0x203}, 257 | {"KEY_NUMERIC_4", 0x204}, 258 | {"KEY_NUMERIC_5", 0x205}, 259 | {"KEY_NUMERIC_6", 0x206}, 260 | {"KEY_NUMERIC_7", 0x207}, 261 | {"KEY_NUMERIC_8", 0x208}, 262 | {"KEY_NUMERIC_9", 0x209}, 263 | {"KEY_NUMERIC_POUND", 0x20b}, 264 | {"KEY_NUMERIC_STAR", 0x20a}, 265 | {"KEY_NUMLOCK", 69}, 266 | {"KEY_O", 24}, 267 | {"KEY_OK", 0x160}, 268 | {"KEY_OPEN", 134}, 269 | {"KEY_OPTION", 0x165}, 270 | {"KEY_P", 25}, 271 | {"KEY_PAGEDOWN", 109}, 272 | {"KEY_PAGEUP", 104}, 273 | {"KEY_PASTE", 135}, 274 | {"KEY_PAUSE", 119}, 275 | {"KEY_PAUSECD", 201}, 276 | {"KEY_PC", 0x178}, 277 | {"KEY_PHONE", 169}, 278 | {"KEY_PLAY", 207}, 279 | {"KEY_PLAYCD", 200}, 280 | {"KEY_PLAYER", 0x183}, 281 | {"KEY_PLAYPAUSE", 164}, 282 | {"KEY_POWER", 116}, 283 | {"KEY_POWER2", 0x164}, 284 | {"KEY_PRESENTATION", 0x1a9}, 285 | {"KEY_PREVIOUS", 0x19c}, 286 | {"KEY_PREVIOUSSONG", 165}, 287 | {"KEY_PRINT", 210}, 288 | {"KEY_PROG1", 148}, 289 | {"KEY_PROG2", 149}, 290 | {"KEY_PROG3", 202}, 291 | {"KEY_PROG4", 203}, 292 | {"KEY_PROGRAM", 0x16a}, 293 | {"KEY_PROPS", 130}, 294 | {"KEY_PVR", 0x16e}, 295 | {"KEY_Q", 16}, 296 | {"KEY_QUESTION", 214}, 297 | {"KEY_R", 19}, 298 | {"KEY_RADIO", 0x181}, 299 | {"KEY_RECORD", 167}, 300 | {"KEY_RED", 0x18e}, 301 | {"KEY_REDO", 182}, 302 | {"KEY_REFRESH", 173}, 303 | {"KEY_REPLY", 232}, 304 | {"KEY_RESERVED", 0}, 305 | {"KEY_RESTART", 0x198}, 306 | {"KEY_REWIND", 168}, 307 | {"KEY_RFKILL", 247}, 308 | {"KEY_RIGHT", 106}, 309 | {"KEY_RIGHTALT", 100}, 310 | {"KEY_RIGHTBRACE", 27}, 311 | {"KEY_RIGHTCTRL", 97}, 312 | {"KEY_RIGHTMETA", 126}, 313 | {"KEY_RIGHTSHIFT", 54}, 314 | {"KEY_RO", 89}, 315 | {"KEY_S", 31}, 316 | {"KEY_SAT", 0x17d}, 317 | {"KEY_SAT2", 0x17e}, 318 | {"KEY_SAVE", 234}, 319 | {"KEY_SCALE", 120}, 320 | {"KEY_SCREEN", 0x177}, 321 | {"KEY_SCROLLDOWN", 178}, 322 | {"KEY_SCROLLLOCK", 70}, 323 | {"KEY_SCROLLUP", 177}, 324 | {"KEY_SEARCH", 217}, 325 | {"KEY_SELECT", 0x161}, 326 | {"KEY_SEMICOLON", 39}, 327 | {"KEY_SEND", 231}, 328 | {"KEY_SENDFILE", 145}, 329 | {"KEY_SETUP", 141}, 330 | {"KEY_SHOP", 221}, 331 | {"KEY_SHUFFLE", 0x19a}, 332 | {"KEY_SLASH", 53}, 333 | {"KEY_SLEEP", 142}, 334 | {"KEY_SLOW", 0x199}, 335 | {"KEY_SOUND", 213}, 336 | {"KEY_SPACE", 57}, 337 | {"KEY_SPELLCHECK", 0x1b0}, 338 | {"KEY_SPORT", 220}, 339 | {"KEY_SPREADSHEET", 0x1a7}, 340 | {"KEY_STOP", 128}, 341 | {"KEY_STOPCD", 166}, 342 | {"KEY_SUBTITLE", 0x172}, 343 | {"KEY_SUSPEND", 205}, 344 | {"KEY_SWITCHVIDEOMODE", 227}, 345 | {"KEY_SYSRQ", 99}, 346 | {"KEY_T", 20}, 347 | {"KEY_TAB", 15}, 348 | {"KEY_TAPE", 0x180}, 349 | {"KEY_TEEN", 0x19e}, 350 | {"KEY_TEXT", 0x184}, 351 | {"KEY_TIME", 0x167}, 352 | {"KEY_TITLE", 0x171}, 353 | {"KEY_TOUCHPAD_OFF", 0x214}, 354 | {"KEY_TOUCHPAD_ON", 0x213}, 355 | {"KEY_TOUCHPAD_TOGGLE", 0x212}, 356 | {"KEY_TUNER", 0x182}, 357 | {"KEY_TV", 0x179}, 358 | {"KEY_TV2", 0x17a}, 359 | {"KEY_TWEN", 0x19f}, 360 | {"KEY_U", 22}, 361 | {"KEY_UNDO", 131}, 362 | {"KEY_UNKNOWN", 240}, 363 | {"KEY_UP", 103}, 364 | {"KEY_UWB", 239}, 365 | {"KEY_V", 47}, 366 | {"KEY_VCR", 0x17b}, 367 | {"KEY_VCR2", 0x17c}, 368 | {"KEY_VENDOR", 0x168}, 369 | {"KEY_VIDEO", 0x189}, 370 | {"KEY_VIDEOPHONE", 0x1a0}, 371 | {"KEY_VIDEO_NEXT", 241}, 372 | {"KEY_VIDEO_PREV", 242}, 373 | {"KEY_VOICEMAIL", 0x1ac}, 374 | {"KEY_VOLUMEDOWN", 114}, 375 | {"KEY_VOLUMEUP", 115}, 376 | {"KEY_W", 17}, 377 | {"KEY_WAKEUP", 143}, 378 | {"KEY_WIMAX", 246}, 379 | {"KEY_WLAN", 238}, 380 | {"KEY_WORDPROCESSOR", 0x1a5}, 381 | {"KEY_WPS_BUTTON", 0x211}, 382 | {"KEY_WWW", 150}, 383 | {"KEY_X", 45}, 384 | {"KEY_XFER", 147}, 385 | {"KEY_Y", 21}, 386 | {"KEY_YELLOW", 0x190}, 387 | {"KEY_YEN", 124}, 388 | {"KEY_Z", 44}, 389 | {"KEY_ZENKAKUHANKAKU", 85}, 390 | {"KEY_ZOOM", 0x174}, 391 | {"KEY_ZOOMIN", 0x1a2}, 392 | {"KEY_ZOOMOUT", 0x1a3}, 393 | {"KEY_ZOOMRESET", 0x1a4}, 394 | {"BTN_0", 0x100}, 395 | {"BTN_1", 0x101}, 396 | {"BTN_2", 0x102}, 397 | {"BTN_3", 0x103}, 398 | {"BTN_4", 0x104}, 399 | {"BTN_5", 0x105}, 400 | {"BTN_6", 0x106}, 401 | {"BTN_7", 0x107}, 402 | {"BTN_8", 0x108}, 403 | {"BTN_9", 0x109}, 404 | {"BTN_A", 0x130}, 405 | {"BTN_B", 0x131}, 406 | {"BTN_BACK", 0x116}, 407 | {"BTN_BASE", 0x126}, 408 | {"BTN_BASE2", 0x127}, 409 | {"BTN_BASE3", 0x128}, 410 | {"BTN_BASE4", 0x129}, 411 | {"BTN_BASE5", 0x12a}, 412 | {"BTN_BASE6", 0x12b}, 413 | {"BTN_C", 0x132}, 414 | {"BTN_DEAD", 0x12f}, 415 | {"BTN_DIGI", 0x140}, 416 | {"BTN_EXTRA", 0x114}, 417 | {"BTN_FORWARD", 0x115}, 418 | {"BTN_GAMEPAD", 0x130}, 419 | {"BTN_GEAR_DOWN", 0x150}, 420 | {"BTN_GEAR_UP", 0x151}, 421 | {"BTN_JOYSTICK", 0x120}, 422 | {"BTN_LEFT", 0x110}, 423 | {"BTN_MIDDLE", 0x112}, 424 | {"BTN_MISC", 0x100}, 425 | {"BTN_MODE", 0x13c}, 426 | {"BTN_MOUSE", 0x110}, 427 | {"BTN_PINKIE", 0x125}, 428 | {"BTN_RIGHT", 0x111}, 429 | {"BTN_SELECT", 0x13a}, 430 | {"BTN_SIDE", 0x113}, 431 | {"BTN_START", 0x13b}, 432 | {"BTN_STYLUS", 0x14b}, 433 | {"BTN_STYLUS2", 0x14c}, 434 | {"BTN_TASK", 0x117}, 435 | {"BTN_THUMB", 0x121}, 436 | {"BTN_THUMB2", 0x122}, 437 | {"BTN_THUMBL", 0x13d}, 438 | {"BTN_THUMBR", 0x13e}, 439 | {"BTN_TL", 0x136}, 440 | {"BTN_TL2", 0x138}, 441 | {"BTN_TOOL_AIRBRUSH", 0x144}, 442 | {"BTN_TOOL_BRUSH", 0x142}, 443 | {"BTN_TOOL_DOUBLETAP", 0x14d}, 444 | {"BTN_TOOL_FINGER", 0x145}, 445 | {"BTN_TOOL_LENS", 0x147}, 446 | {"BTN_TOOL_MOUSE", 0x146}, 447 | {"BTN_TOOL_PEN", 0x140}, 448 | {"BTN_TOOL_PENCIL", 0x143}, 449 | {"BTN_TOOL_QUADTAP", 0x14f}, 450 | {"BTN_TOOL_QUINTTAP", 0x148}, 451 | {"BTN_TOOL_RUBBER", 0x141}, 452 | {"BTN_TOOL_TRIPLETAP", 0x14e}, 453 | {"BTN_TOP", 0x123}, 454 | {"BTN_TOP2", 0x124}, 455 | {"BTN_TOUCH", 0x14a}, 456 | {"BTN_TR", 0x137}, 457 | {"BTN_TR2", 0x139}, 458 | {"BTN_TRIGGER", 0x120}, 459 | {"BTN_TRIGGER_HAPPY", 0x2c0}, 460 | {"BTN_TRIGGER_HAPPY1", 0x2c0}, 461 | {"BTN_TRIGGER_HAPPY10", 0x2c9}, 462 | {"BTN_TRIGGER_HAPPY11", 0x2ca}, 463 | {"BTN_TRIGGER_HAPPY12", 0x2cb}, 464 | {"BTN_TRIGGER_HAPPY13", 0x2cc}, 465 | {"BTN_TRIGGER_HAPPY14", 0x2cd}, 466 | {"BTN_TRIGGER_HAPPY15", 0x2ce}, 467 | {"BTN_TRIGGER_HAPPY16", 0x2cf}, 468 | {"BTN_TRIGGER_HAPPY17", 0x2d0}, 469 | {"BTN_TRIGGER_HAPPY18", 0x2d1}, 470 | {"BTN_TRIGGER_HAPPY19", 0x2d2}, 471 | {"BTN_TRIGGER_HAPPY2", 0x2c1}, 472 | {"BTN_TRIGGER_HAPPY20", 0x2d3}, 473 | {"BTN_TRIGGER_HAPPY21", 0x2d4}, 474 | {"BTN_TRIGGER_HAPPY22", 0x2d5}, 475 | {"BTN_TRIGGER_HAPPY23", 0x2d6}, 476 | {"BTN_TRIGGER_HAPPY24", 0x2d7}, 477 | {"BTN_TRIGGER_HAPPY25", 0x2d8}, 478 | {"BTN_TRIGGER_HAPPY26", 0x2d9}, 479 | {"BTN_TRIGGER_HAPPY27", 0x2da}, 480 | {"BTN_TRIGGER_HAPPY28", 0x2db}, 481 | {"BTN_TRIGGER_HAPPY29", 0x2dc}, 482 | {"BTN_TRIGGER_HAPPY3", 0x2c2}, 483 | {"BTN_TRIGGER_HAPPY30", 0x2dd}, 484 | {"BTN_TRIGGER_HAPPY31", 0x2de}, 485 | {"BTN_TRIGGER_HAPPY32", 0x2df}, 486 | {"BTN_TRIGGER_HAPPY33", 0x2e0}, 487 | {"BTN_TRIGGER_HAPPY34", 0x2e1}, 488 | {"BTN_TRIGGER_HAPPY35", 0x2e2}, 489 | {"BTN_TRIGGER_HAPPY36", 0x2e3}, 490 | {"BTN_TRIGGER_HAPPY37", 0x2e4}, 491 | {"BTN_TRIGGER_HAPPY38", 0x2e5}, 492 | {"BTN_TRIGGER_HAPPY39", 0x2e6}, 493 | {"BTN_TRIGGER_HAPPY4", 0x2c3}, 494 | {"BTN_TRIGGER_HAPPY40", 0x2e7}, 495 | {"BTN_TRIGGER_HAPPY5", 0x2c4}, 496 | {"BTN_TRIGGER_HAPPY6", 0x2c5}, 497 | {"BTN_TRIGGER_HAPPY7", 0x2c6}, 498 | {"BTN_TRIGGER_HAPPY8", 0x2c7}, 499 | {"BTN_TRIGGER_HAPPY9", 0x2c8}, 500 | {"BTN_WHEEL", 0x150}, 501 | {"BTN_X", 0x133}, 502 | {"BTN_Y", 0x134}, 503 | {"BTN_Z", 0x135}, 504 | -------------------------------------------------------------------------------- /Clock/.gitignore: -------------------------------------------------------------------------------- 1 | /ApiKeys.py 2 | /Config-Chris.py 3 | /Config-Jean.py 4 | /Config-Kelly.py 5 | /Config.py 6 | /Config-jcwho.py 7 | /Config-Bedside.py 8 | /Config-7in-night.py 9 | /Config-7in-day.py 10 | -------------------------------------------------------------------------------- /Clock/ApiKeys-example.py: -------------------------------------------------------------------------------- 1 | # change this to your API keys 2 | # 3 | # Map API keys -- only needs 1 of the following 4 | # Google Maps API key (if usemapbox is not set in Config) 5 | googleapi = 'YOUR GOOGLE MAPS API KEY' 6 | # 7 | # Mapbox API key (access_token) [if usemapbox is set in Config] 8 | mbapi = 'YOUR MAPBOX ACCESS TOKEN' 9 | # 10 | # If you want to use Openweathermap.org, uncomment and add appid 11 | owmapi = 'YOUR OPENWEATHERMAP APPID' 12 | # 13 | # If you want to use tomorrow.io, uncomment and add appid 14 | # also comment/remove owmapi if you're using tomorrow.io 15 | # tmapi = 'YOUR tomorrow.io API KEY' 16 | -------------------------------------------------------------------------------- /Clock/Config-Example-Bedside.py: -------------------------------------------------------------------------------- 1 | from GoogleMercatorProjection import LatLng 2 | from PyQt4.QtGui import QColor 3 | 4 | # LOCATION(S) 5 | # Further radar configuration (zoom, marker location) 6 | # can be completed under the RADAR section 7 | primary_coordinates = 44.9764016, -93.2486732 # Change to your Lat/Lon 8 | 9 | # Location for weather report 10 | location = LatLng(primary_coordinates[0], primary_coordinates[1]) 11 | # Default radar location 12 | primary_location = LatLng(primary_coordinates[0], primary_coordinates[1]) 13 | noaastream = 'http://www.urberg.net:8000/tim273/edina' 14 | background = 'images/bb.jpg' 15 | squares1 = 'images/squares1-green.png' 16 | squares2 = 'images/squares2-green.png' 17 | icons = 'icons-darkgreen' 18 | textcolor = '#206225' 19 | clockface = 'images/clockface3-darkgreen.png' 20 | hourhand = 'images/hourhand-darkgreen.png' 21 | minhand = 'images/minhand-darkgreen.png' 22 | sechand = 'images/sechand-darkgreen.png' 23 | 24 | digital = 0 # 1 = Digtal Clock, 0 = Analog Clock 25 | 26 | digitalcolor = "#154018" 27 | digitalformat = "{0:%I:%M\n%S %p}" # The format of the time 28 | digitalsize = 200 29 | # The above example shows in this way: 30 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v1.jpg 31 | # ( specifications of the time string are documented here: 32 | # https://docs.python.org/2/library/time.html#time.strftime ) 33 | 34 | # digitalformat = "{0:%I:%M}" 35 | # digitalsize = 250 36 | # The above example shows in this way: 37 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v2.jpg 38 | 39 | 40 | # 0 = English, 1 = Metric 41 | metric = 0 42 | 43 | # minutes 44 | radar_refresh = 10 45 | 46 | # minutes 47 | weather_refresh = 30 48 | 49 | # Wind in degrees instead of cardinal 0 = cardinal, 1 = degrees 50 | wind_degrees = 0 51 | 52 | # Font attribute applied globally 53 | fontattr = 'font-weight: bold; ' 54 | 55 | # These are to dim the radar images, if needed. 56 | dimcolor = QColor('#103125') 57 | dimcolor.setAlpha(192) 58 | 59 | # Language Specific wording 60 | # DarkSky Language code 61 | # (https://darksky.net/dev/docs under lang=) 62 | Language = "EN" 63 | 64 | # The Python Locale for date/time (locale.setlocale) 65 | # '' for default Pi Setting 66 | # Locales must be installed in your Pi.. to check what is installed 67 | # locale -a 68 | # to install locales 69 | # sudo dpkg-reconfigure locales 70 | DateLocale = '' 71 | 72 | # Language specific wording 73 | LPressure = "Pressure " 74 | LHumidity = "Humidity " 75 | LWind = "Wind " 76 | Lgusting = " gusting " 77 | LFeelslike = "Feels like " 78 | LPrecip1hr = " Precip 1hr:" 79 | LToday = "Today: " 80 | LSunRise = "Sun Rise:" 81 | LSet = " Set: " 82 | LMoonPhase = " Moon Phase:" 83 | LInsideTemp = "Inside Temp " 84 | LRain = " Rain: " 85 | LSnow = " Snow: " 86 | 87 | 88 | # RADAR 89 | # By default, primary_location entered will be the center and marker of all 90 | # radar images. 91 | # To update centers/markers, change radar sections 92 | # below the desired lat/lon as: 93 | # -FROM- 94 | # primary_location, 95 | # -TO- 96 | # LatLng(44.9764016,-93.2486732), 97 | radar1 = { 98 | 'center': primary_location, # the center of your radar block 99 | 'zoom': 7, # this is a google maps zoom factor, bigger = smaller area 100 | 'style': 'mapbox/cj5l80zrp29942rmtg0zctjto', # Mapbox calls this Decimal 101 | 'markers': ( # google maps markers can be overlayed 102 | { 103 | 'location': primary_location, 104 | 'color': 'red', 105 | 'size': 'small', 106 | }, # dangling comma is on purpose. 107 | ) 108 | } 109 | 110 | 111 | radar2 = { 112 | 'center': primary_location, 113 | 'zoom': 11, 114 | 'style': 'mapbox/cj5l80zrp29942rmtg0zctjto', # Mapbox calls this Decimal 115 | 'markers': ( 116 | { 117 | 'location': primary_location, 118 | 'color': 'red', 119 | 'size': 'small', 120 | }, 121 | ) 122 | } 123 | 124 | 125 | radar3 = { 126 | 'center': primary_location, 127 | 'zoom': 7, 128 | 'style': 'mapbox/cj5l80zrp29942rmtg0zctjto', # Mapbox calls this Decimal 129 | 'markers': ( 130 | { 131 | 'location': primary_location, 132 | 'color': 'red', 133 | 'size': 'small', 134 | }, 135 | ) 136 | } 137 | 138 | radar4 = { 139 | 'center': primary_location, 140 | 'zoom': 11, 141 | 'style': 'mapbox/cj5l80zrp29942rmtg0zctjto', # Mapbox calls this Decimal 142 | 'markers': ( 143 | { 144 | 'location': primary_location, 145 | 'color': 'red', 146 | 'size': 'small', 147 | }, 148 | ) 149 | } 150 | -------------------------------------------------------------------------------- /Clock/Config-Example-Berlin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from GoogleMercatorProjection import LatLng 3 | from PyQt4.QtGui import QColor 4 | 5 | # LOCATION(S) 6 | # Further radar configuration (zoom, marker location) can be 7 | # completed under the RADAR section 8 | primary_coordinates = 52.5074559, 13.144557 # Change to your Lat/Lon 9 | 10 | location = LatLng(primary_coordinates[0], primary_coordinates[1]) 11 | primary_location = LatLng(primary_coordinates[0], primary_coordinates[1]) 12 | noaastream = '' 13 | background = 'images/berlin-at-night-mrwallpaper.jpg' 14 | squares1 = 'images/squares1-kevin.png' 15 | squares2 = 'images/squares2-kevin.png' 16 | icons = 'icons-lightblue' 17 | textcolor = '#bef' 18 | clockface = 'images/clockface3.png' 19 | hourhand = 'images/hourhand.png' 20 | minhand = 'images/minhand.png' 21 | sechand = 'images/sechand.png' 22 | 23 | 24 | digital = 0 # 1 = Digtal Clock, 0 = Analog Clock 25 | 26 | # Goes with light blue config (like the default one) 27 | digitalcolor = "#50CBEB" 28 | digitalformat = "{0:%I:%M\n%S %p}" # The format of the time 29 | digitalsize = 200 30 | # The above example shows in this way: 31 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v1.jpg 32 | # ( specifications of the time string are documented here: 33 | # https://docs.python.org/2/library/time.html#time.strftime ) 34 | 35 | # digitalformat = "{0:%I:%M}" 36 | # digitalsize = 250 37 | # The above example shows in this way: 38 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v2.jpg 39 | 40 | 41 | metric = 1 # 0 = English, 1 = Metric 42 | radar_refresh = 10 # minutes 43 | weather_refresh = 30 # minutes 44 | # Wind in degrees instead of cardinal 0 = cardinal, 1 = degrees 45 | wind_degrees = 0 46 | 47 | 48 | # gives all text additional attributes using QT style notation 49 | # example: fontattr = 'font-weight: bold; ' 50 | fontattr = '' 51 | 52 | # These are to dim the radar images, if needed. 53 | # see and try Config-Example-Bedside.py 54 | dimcolor = QColor('#000000') 55 | dimcolor.setAlpha(0) 56 | 57 | METAR="" 58 | 59 | # Language Specific wording 60 | # OpenWeatherMap Language code 61 | # (https://openweathermap.org/current#multi) 62 | Language = "DE" 63 | 64 | # The Python Locale for date/time (locale.setlocale) 65 | # '' for default Pi Setting 66 | # Locales must be installed in your Pi.. to check what is installed 67 | # locale -a 68 | # to install locales 69 | # sudo dpkg-reconfigure locales 70 | DateLocale = 'de_DE.utf-8' 71 | 72 | # Language specific wording 73 | # thanks to colonia27 for the language work 74 | LPressure = "Luftdruck " 75 | LHumidity = "Feuchtigkeit " 76 | LWind = "Wind " 77 | Lgusting = u" böen " 78 | LFeelslike = u"Gefühlt " 79 | LPrecip1hr = " Niederschlag 1h:" 80 | LToday = "Heute: " 81 | LSunRise = "Sonnenaufgang:" 82 | LSet = " unter: " 83 | LMoonPhase = " Mond Phase:" 84 | LInsideTemp = "Innen Temp " 85 | LRain = " Regen: " 86 | LSnow = " Schnee: " 87 | Lmoon1 = 'Neumond' 88 | Lmoon2 = 'Zunehmender Sichelmond' 89 | Lmoon3 = 'Zunehmender Halbmond' 90 | Lmoon4 = 'Zunehmender Dreiviertelmond' 91 | Lmoon5 = 'Vollmond ' 92 | Lmoon6 = 'Abnehmender Dreiviertelmond' 93 | Lmoon7 = 'Abnehmender Halbmond' 94 | Lmoon8 = 'Abnehmender Sichelmond' 95 | # Language Specific terms for weather conditions 96 | 97 | 98 | Ltm_code_map = { 99 | 0: 'Unknown', 100 | 1000: "Klar", 101 | 1100: 'Teilweise klar', 102 | 1101: 'Teilweise Wolkig', 103 | 1102: 'Meist Wolkig', 104 | 1001: 'Wolkig', 105 | 2000: 'Nebel', 106 | 2100: 'Leichter Nebel', 107 | 4000: 'Nieselregen', 108 | 4001: 'Rain', 109 | 4200: 'Light Rain', 110 | 4201: 'Heavy Rain', 111 | 5000: 'Regen', 112 | 5001: 'Gewitter', 113 | 5100: 'Leichter Schnee', 114 | 5101: 'Starker Schneefall', 115 | 6000: 'Gefrierender Nieselregen', 116 | 6001: 'Gefrierender Regen', 117 | 6200: 'Gefrierender Regen', 118 | 6201: 'Gefrierender Regen', 119 | 7000: 'Eisstücke', 120 | 7101: 'Eisstücke', 121 | 7102: 'Eisstücke', 122 | 8000: 'Gewitter' 123 | } 124 | 125 | 126 | # RADAR 127 | # By default, primary_location entered will be the 128 | # center and marker of all radar images. 129 | # To update centers/markers, change radar sections 130 | # below the desired lat/lon as: 131 | # -FROM- 132 | # primary_location, 133 | # -TO- 134 | # LatLng(44.9764016,-93.2486732), 135 | radar1 = { 136 | 'center': primary_location, # the center of your radar block 137 | 'zoom': 7, # this is a google maps zoom factor, bigger = smaller area 138 | 'markers': ( # google maps markers can be overlayed 139 | { 140 | 'location': primary_location, 141 | 'color': 'red', 142 | 'size': 'small', 143 | }, # dangling comma is on purpose. 144 | ) 145 | } 146 | 147 | 148 | radar2 = { 149 | 'center': primary_location, 150 | 'zoom': 11, 151 | 'markers': ( 152 | { 153 | 'location': primary_location, 154 | 'color': 'red', 155 | 'size': 'small', 156 | }, 157 | ) 158 | } 159 | 160 | 161 | radar3 = { 162 | 'center': primary_location, 163 | 'zoom': 7, 164 | 'markers': ( 165 | { 166 | 'location': primary_location, 167 | 'color': 'red', 168 | 'size': 'small', 169 | }, 170 | ) 171 | } 172 | 173 | radar4 = { 174 | 'center': primary_location, 175 | 'zoom': 11, 176 | 'markers': ( 177 | { 178 | 'location': primary_location, 179 | 'color': 'red', 180 | 'size': 'small', 181 | }, 182 | ) 183 | } 184 | -------------------------------------------------------------------------------- /Clock/Config-Example-London.py: -------------------------------------------------------------------------------- 1 | from GoogleMercatorProjection import LatLng # NOQA 2 | from PyQt4.QtGui import QColor 3 | 4 | 5 | # LOCATION(S) 6 | # Further radar configuration (zoom, marker location) can be 7 | # completed under the RADAR section 8 | primary_coordinates = 51.5286416, -0.1015987 # Change to your Lat/Lon 9 | 10 | location = LatLng(primary_coordinates[0], primary_coordinates[1]) 11 | primary_location = LatLng(primary_coordinates[0], primary_coordinates[1]) 12 | noaastream = '???' 13 | background = 'images/london-at-night-wallpapers.jpg' 14 | squares1 = 'images/squares1-kevin.png' 15 | squares2 = 'images/squares2-kevin.png' 16 | icons = 'icons-lightblue' 17 | textcolor = '#bef' 18 | clockface = 'images/clockface3.png' 19 | hourhand = 'images/hourhand.png' 20 | minhand = 'images/minhand.png' 21 | sechand = 'images/sechand.png' 22 | 23 | 24 | digital = 0 # 1 = Digtal Clock, 0 = Analog Clock 25 | 26 | # Goes with light blue config (like the default one) 27 | digitalcolor = "#50CBEB" 28 | digitalformat = "{0:%I:%M\n%S %p}" # The format of the time 29 | digitalsize = 200 30 | # The above example shows in this way: 31 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v1.jpg 32 | # ( specifications of the time string are documented here: 33 | # https://docs.python.org/2/library/time.html#time.strftime ) 34 | 35 | # digitalformat = "{0:%I:%M}" 36 | # digitalsize = 250 37 | # The above example shows in this way: 38 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v2.jpg 39 | 40 | 41 | metric = 1 # 0 = English, 1 = Metric 42 | radar_refresh = 10 # minutes 43 | weather_refresh = 30 # minutes 44 | # Wind in degrees instead of cardinal 0 = cardinal, 1 = degrees 45 | wind_degrees = 0 46 | 47 | # gives all text additional attributes using QT style notation 48 | # example: fontattr = 'font-weight: bold; ' 49 | fontattr = '' 50 | 51 | # These are to dim the radar images, if needed. 52 | # see and try Config-Example-Bedside.py 53 | dimcolor = QColor('#000000') 54 | dimcolor.setAlpha(0) 55 | 56 | METAR="EGLL" # LHR London Heathrow Airport 57 | 58 | # Language Specific wording 59 | # DarkSky Language code 60 | # (https://darksky.net/dev/docs under lang=) 61 | Language = "EN" 62 | 63 | # The Python Locale for date/time (locale.setlocale) 64 | # '' for default Pi Setting 65 | # Locales must be installed in your Pi.. to check what is installed 66 | # locale -a 67 | # to install locales 68 | # sudo dpkg-reconfigure locales 69 | DateLocale = '' 70 | 71 | # Language specific wording 72 | LPressure = "Pressure " 73 | LHumidity = "Humidity " 74 | LWind = "Wind " 75 | Lgusting = " gusting " 76 | LFeelslike = "Feels like " 77 | LPrecip1hr = " Precip 1hr:" 78 | LToday = "Today: " 79 | LSunRise = "Sun Rise:" 80 | LSet = " Set: " 81 | LMoonPhase = " Moon Phase:" 82 | LInsideTemp = "Inside Temp " 83 | LRain = " Rain: " 84 | LSnow = " Snow: " 85 | 86 | 87 | # RADAR 88 | # By default, primary_location entered will be the 89 | # center and marker of all radar images. 90 | # To update centers/markers,change radar sections below the desired lat/lon as: 91 | # -FROM- 92 | # primary_location, 93 | # -TO- 94 | # LatLng(44.9764016,-93.2486732), 95 | radar1 = { 96 | 'center': primary_location, # the center of your radar block 97 | 'zoom': 7, # this is a google maps zoom factor, bigger = smaller area 98 | 'markers': ( # google maps markers can be overlayed 99 | { 100 | 'location': primary_location, 101 | 'color': 'red', 102 | 'size': 'small', 103 | }, # dangling comma is on purpose. 104 | ) 105 | } 106 | 107 | 108 | radar2 = { 109 | 'center': primary_location, 110 | 'zoom': 11, 111 | 'markers': ( 112 | { 113 | 'location': primary_location, 114 | 'color': 'red', 115 | 'size': 'small', 116 | }, 117 | ) 118 | } 119 | 120 | 121 | radar3 = { 122 | 'center': primary_location, 123 | 'zoom': 7, 124 | 'markers': ( 125 | { 126 | 'location': primary_location, 127 | 'color': 'red', 128 | 'size': 'small', 129 | }, 130 | ) 131 | } 132 | 133 | radar4 = { 134 | 'center': primary_location, 135 | 'zoom': 11, 136 | 'markers': ( 137 | { 138 | 'location': primary_location, 139 | 'color': 'red', 140 | 'size': 'small', 141 | }, 142 | ) 143 | } 144 | -------------------------------------------------------------------------------- /Clock/Config-Example.py: -------------------------------------------------------------------------------- 1 | from GoogleMercatorProjection import LatLng 2 | from PyQt4.QtGui import QColor 3 | 4 | 5 | # LOCATION(S) 6 | # Further radar configuration (zoom, marker location) can be 7 | # completed under the RADAR section 8 | primary_coordinates = 44.9764016, -93.2486732 # Change to your Lat/Lon 9 | 10 | location = LatLng(primary_coordinates[0], primary_coordinates[1]) 11 | primary_location = LatLng(primary_coordinates[0], primary_coordinates[1]) 12 | noaastream = 'http://www.urberg.net:8000/tim273/edina' 13 | background = 'images/clockbackground-kevin.png' 14 | squares1 = 'images/squares1-kevin.png' 15 | squares2 = 'images/squares2-kevin.png' 16 | icons = 'icons-lightblue' 17 | textcolor = '#bef' 18 | clockface = 'images/clockface3.png' 19 | hourhand = 'images/hourhand.png' 20 | minhand = 'images/minhand.png' 21 | sechand = 'images/sechand.png' 22 | 23 | # SlideShow 24 | useslideshow = 0 # 1 to enable, 0 to disable 25 | slide_time = 305 # in seconds, 3600 per hour 26 | slides = 'images/slideshow' # the path to your local images 27 | slide_bg_color = "#000" # https://htmlcolorcodes.com/ black #000 28 | 29 | digital = 0 # 1 = Digtal Clock, 0 = Analog Clock 30 | 31 | # Goes with light blue config (like the default one) 32 | digitalcolor = "#50CBEB" 33 | digitalformat = "{0:%I:%M\n%S %p}" # Format of the digital clock face 34 | digitalsize = 200 35 | 36 | # The above example shows in this way: 37 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v1.jpg 38 | # ( specifications of the time string are documented here: 39 | # https://docs.python.org/2/library/time.html#time.strftime ) 40 | 41 | # digitalformat = "{0:%I:%M}" 42 | # digitalsize = 250 43 | # The above example shows in this way: 44 | # https://github.com/n0bel/PiClock/blob/master/Documentation/Digital%20Clock%20v2.jpg 45 | 46 | digitalformat2 = "{0:%H:%M:%S}" # Format of the digital time on second screen 47 | 48 | clockUTC = 0 # Clock (analog/digital/top date) to display in UTC regardless of PiOS timezone 49 | 50 | usemapbox = 0 # Use Mapbox.com for maps, needs api key (mbapi in ApiKeys.py) 51 | metric = 0 # 0 = English, 1 = Metric 52 | radar_refresh = 10 # minutes 53 | weather_refresh = 30 # minutes 54 | # Wind in degrees instead of cardinal 0 = cardinal, 1 = degrees 55 | wind_degrees = 0 56 | 57 | # gives all text additional attributes using QT style notation 58 | # example: fontattr = 'font-weight: bold; ' 59 | fontattr = '' 60 | 61 | # These are to dim the radar images, if needed. 62 | # see and try Config-Example-Bedside.py 63 | dimcolor = QColor('#000000') 64 | dimcolor.setAlpha(0) 65 | 66 | # Optional Current conditions replaced with observations from a METAR station 67 | # METAR is world wide, provided mostly for pilots 68 | # But data can be sparse outside US and Europe 69 | # If you're close to an international airport, you should find soemthing close 70 | # Find the closest METAR station with the following URL 71 | # https://www.aviationweather.gov/metar 72 | # scroll/zoom the map to find your closest station 73 | # or look up the ICAO code here: 74 | # https://airportcodes.aero/name 75 | METAR = '' 76 | 77 | # Language Specific wording 78 | # DarkSky Language code 79 | # (https://darksky.net/dev/docs under lang=) 80 | Language = "EN" 81 | 82 | # The Python Locale for date/time (locale.setlocale) 83 | # '' for default Pi Setting 84 | # Locales must be installed in your Pi.. to check what is installed 85 | # locale -a 86 | # to install locales 87 | # sudo dpkg-reconfigure locales 88 | DateLocale = '' 89 | 90 | # Language specific wording 91 | LPressure = "Pressure " 92 | LHumidity = "Humidity " 93 | LWind = "Wind " 94 | Lgusting = " gust " 95 | LFeelslike = "Feels like " 96 | LPrecip1hr = " Precip 1hr: " 97 | LToday = "Today: " 98 | LSunRise = "Sun Rise: " 99 | LSet = " Set: " 100 | LMoonPhase = " Moon: " 101 | LInsideTemp = "Inside Temp " 102 | LRain = " Rain: " 103 | LSnow = " Snow: " 104 | Lmoon1 = 'New Moon' 105 | Lmoon2 = 'Waxing Crescent' 106 | Lmoon3 = 'First Quarter' 107 | Lmoon4 = 'Waxing Gibbous' 108 | Lmoon5 = 'Full Moon' 109 | Lmoon6 = 'Waning Gibbous' 110 | Lmoon7 = 'Third Quarter' 111 | Lmoon8 = 'Waning Crecent' 112 | # Language Specific terms for weather conditions 113 | Lcc_code_map = { 114 | "freezing_rain_heavy": "Freezing Rain", 115 | "freezing_rain": "Freezing Rain", 116 | "freezing_rain_light": "Freezing Rain", 117 | "freezing_drizzle": "Freezing Drizzle", 118 | "ice_pellets_heavy": "Ice Pellets", 119 | "ice_pellets": "Ice Pellets", 120 | "ice_pellets_light": "Ice Pellets", 121 | "snow_heavy": "Heavy Snow", 122 | "snow": "Snow", 123 | "snow_light": "Light Snow", 124 | "flurries": "Flurries", 125 | "tstorm": "Thunder Storm", 126 | "rain_heavy": "Heavy Rain", 127 | "rain": "Rain", 128 | "rain_light": "Light Rain", 129 | "drizzle": "Drizzle", 130 | "fog_light": "Light Fog", 131 | "fog": "Fog", 132 | "cloudy": "Cloudy", 133 | "mostly_cloudy": "Mostly Cloudy", 134 | "partly_cloudy": "Partly Cloudy", 135 | "mostly_clear": "Mostly Clear", 136 | "clear": "Clear" 137 | } 138 | 139 | # RADAR 140 | # By default, primary_location entered will be the 141 | # center and marker of all radar images. 142 | # To update centers/markers, change radar sections 143 | # below the desired lat/lon as: 144 | # -FROM- 145 | # primary_location, 146 | # -TO- 147 | # LatLng(44.9764016,-93.2486732), 148 | radar1 = { 149 | 'center': primary_location, # the center of your radar block 150 | 'zoom': 7, # this is a maps zoom factor, bigger = smaller area 151 | 'style': 'mapbox/satellite-streets-v10', # optional style (mapbox only) 152 | 'color': 6, # rainviewer radar color style: 153 | # https://www.rainviewer.com/api.html#colorSchemes 154 | 'smooth': 1, # rainviewer radar smoothing 155 | 'snow': 1, # rainviewer radar show snow as different color 156 | 'markers': ( # google maps markers can be overlayed 157 | { 158 | 'visible': 1, # 0 = hide marker, 1 = show marker 159 | 'location': primary_location, 160 | 'color': 'red', 161 | 'size': 'small', 162 | 'image': 'teardrop-dot', # optional image from the markers folder 163 | }, # dangling comma is on purpose. 164 | ) 165 | } 166 | 167 | 168 | radar2 = { 169 | 'center': primary_location, 170 | 'zoom': 11, 171 | 'style': 'mapbox/satellite-streets-v10', 172 | 'color': 6, 173 | 'smooth': 1, 174 | 'snow': 1, 175 | 'markers': ( 176 | { 177 | 'visible': 1, 178 | 'location': primary_location, 179 | 'color': 'red', 180 | 'size': 'small', 181 | 'image': 'teardrop-dot', 182 | }, 183 | ) 184 | } 185 | 186 | 187 | radar3 = { 188 | 'center': primary_location, 189 | 'zoom': 7, 190 | 'style': 'mapbox/satellite-streets-v10', 191 | 'color': 6, 192 | 'smooth': 1, 193 | 'snow': 1, 194 | 'markers': ( 195 | { 196 | 'visible': 1, 197 | 'location': primary_location, 198 | 'color': 'red', 199 | 'size': 'small', 200 | 'image': 'teardrop-dot', 201 | }, 202 | ) 203 | } 204 | 205 | radar4 = { 206 | 'center': primary_location, 207 | 'zoom': 11, 208 | 'style': 'mapbox/satellite-streets-v10', 209 | 'color': 6, 210 | 'smooth': 1, 211 | 'snow': 1, 212 | 'markers': ( 213 | { 214 | 'visible': 1, 215 | 'location': primary_location, 216 | 'color': 'red', 217 | 'size': 'small', 218 | 'image': 'teardrop-dot', 219 | }, 220 | ) 221 | } 222 | -------------------------------------------------------------------------------- /Clock/GoogleMercatorProjection.py: -------------------------------------------------------------------------------- 1 | # http://stackoverflow.com/ 2 | # questions/12507274/how-to-get-bounds-of-a-google-static-map 3 | import math 4 | MERCATOR_RANGE = 256 5 | 6 | 7 | def bound(value, opt_min, opt_max): 8 | if (opt_min is not None): 9 | value = max(value, opt_min) 10 | if (opt_max is not None): 11 | value = min(value, opt_max) 12 | return value 13 | 14 | 15 | def degreesToRadians(deg): 16 | return deg * (math.pi / 180) 17 | 18 | 19 | def radiansToDegrees(rad): 20 | return rad / (math.pi / 180) 21 | 22 | 23 | class Point: 24 | def __init__(self, x=0, y=0): 25 | self.x = x 26 | self.y = y 27 | 28 | def __repr__(self): 29 | return "Point(%d,%d)" % (self.x, self.y) 30 | 31 | def __str__(self): 32 | return "(x=%d,y=%d)" % (self.x, self.y) 33 | 34 | 35 | class LatLng: 36 | def __init__(self, lt, ln): 37 | self.lat = lt 38 | self.lng = ln 39 | 40 | def __repr__(self): 41 | return "LatLng(%g,%g)" % (self.lat, self.lng) 42 | 43 | def __str__(self): 44 | return "(lat=%g,lng=%g)" % (self.lat, self.lng) 45 | 46 | 47 | class MercatorProjection: 48 | 49 | def __init__(self): 50 | self.pixelOrigin_ = Point(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0) 51 | self.pixelsPerLonDegree_ = MERCATOR_RANGE / 360.0 52 | self.pixelsPerLonRadian_ = MERCATOR_RANGE / (2.0 * math.pi) 53 | 54 | def fromLatLngToPoint(self, latLng, opt_point=None): 55 | point = opt_point if opt_point is not None else Point(0, 0) 56 | origin = self.pixelOrigin_ 57 | point.x = origin.x + latLng.lng * self.pixelsPerLonDegree_ 58 | # NOTE(appleton): Truncating to 0.9999 effectively limits latitude to 59 | # 89.189.This is about a third of a tile past the edge of world tile 60 | siny = bound(math.sin(degreesToRadians(latLng.lat)), -0.9999, 0.9999) 61 | point.y = origin.y + 0.5 * math.log((1 + siny) / (1.0 - siny)) * \ 62 | -self.pixelsPerLonRadian_ 63 | return point 64 | 65 | def fromPointToLatLng(self, point): 66 | origin = self.pixelOrigin_ 67 | lng = (point.x - origin.x) / self.pixelsPerLonDegree_ 68 | latRadians = (point.y - origin.y) / -self.pixelsPerLonRadian_ 69 | lat = radiansToDegrees(2.0 * math.atan(math.exp(latRadians)) - 70 | math.pi / 2.0) 71 | return LatLng(lat, lng) 72 | 73 | 74 | def getPoint(point, center, zoom, mapWidth, mapHeight): 75 | scale = 2.0**zoom 76 | proj = MercatorProjection() 77 | centerP = proj.fromLatLngToPoint(center) 78 | centerP.x = centerP.x * scale 79 | centerP.y = centerP.y * scale 80 | subjectP = proj.fromLatLngToPoint(point) 81 | subjectP.x = subjectP.x * scale 82 | subjectP.y = subjectP.y * scale 83 | return Point((subjectP.x - centerP.x) + mapWidth / 2.0, 84 | (subjectP.y - centerP.y) + mapHeight / 2.0) 85 | 86 | 87 | def getCorners(center, zoom, mapWidth, mapHeight): 88 | scale = 2.0**zoom 89 | proj = MercatorProjection() 90 | centerPx = proj.fromLatLngToPoint(center) 91 | SWPoint = Point(centerPx.x - (mapWidth / 2.0) / scale, centerPx.y + 92 | (mapHeight / 2.0) / scale) 93 | SWLatLon = proj.fromPointToLatLng(SWPoint) 94 | NEPoint = Point(centerPx.x + (mapWidth / 2.0) / scale, centerPx.y - 95 | (mapHeight / 2.0) / scale) 96 | NELatLon = proj.fromPointToLatLng(NEPoint) 97 | return { 98 | 'N': NELatLon.lat, 99 | 'E': NELatLon.lng, 100 | 'S': SWLatLon.lat, 101 | 'W': SWLatLon.lng, 102 | } 103 | 104 | 105 | # https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames 106 | 107 | def getTileXY(latLng, zoom): 108 | lat_rad = math.radians(latLng.lat) 109 | n = 2.0 ** zoom 110 | xtile = (latLng.lng + 180.0) / 360.0 * n 111 | ytile = ((1.0 - math.log(math.tan(lat_rad) + 112 | (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n) 113 | return { 114 | 'X': xtile, 115 | 'Y': ytile 116 | } 117 | -------------------------------------------------------------------------------- /Clock/icons-darkblue/.gitignore: -------------------------------------------------------------------------------- 1 | /Thumbs.db 2 | -------------------------------------------------------------------------------- /Clock/icons-darkblue/clear-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/clear-day.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/clear-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/clear-night.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/cloudy.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/fog.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/partly-cloudy-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/partly-cloudy-day.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/partly-cloudy-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/partly-cloudy-night.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/rain.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/sleet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/sleet.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/snow.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/thunderstorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/thunderstorm.png -------------------------------------------------------------------------------- /Clock/icons-darkblue/wind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkblue/wind.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/clear-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/clear-day.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/clear-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/clear-night.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/cloudy.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/fog.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/partly-cloudy-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/partly-cloudy-day.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/partly-cloudy-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/partly-cloudy-night.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/rain.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/sleet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/sleet.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/snow.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/thunderstorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/thunderstorm.png -------------------------------------------------------------------------------- /Clock/icons-darkgreen/wind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-darkgreen/wind.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/.gitignore: -------------------------------------------------------------------------------- 1 | /Thumbs.db 2 | -------------------------------------------------------------------------------- /Clock/icons-lightblue/clear-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/clear-day.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/clear-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/clear-night.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/cloudy.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/fog.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/partly-cloudy-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/partly-cloudy-day.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/partly-cloudy-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/partly-cloudy-night.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/rain.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/sleet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/sleet.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/snow.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/thunderstorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/thunderstorm.png -------------------------------------------------------------------------------- /Clock/icons-lightblue/wind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/icons-lightblue/wind.png -------------------------------------------------------------------------------- /Clock/images/.gitignore: -------------------------------------------------------------------------------- 1 | /Thumbs.db 2 | /london-at-night-wallpapers.jpg 3 | -------------------------------------------------------------------------------- /Clock/images/berlin-at-night-mrwallpaper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/berlin-at-night-mrwallpaper.jpg -------------------------------------------------------------------------------- /Clock/images/clockbackground-chris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockbackground-chris.png -------------------------------------------------------------------------------- /Clock/images/clockbackground-jean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockbackground-jean.png -------------------------------------------------------------------------------- /Clock/images/clockbackground-kelly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockbackground-kelly.png -------------------------------------------------------------------------------- /Clock/images/clockbackground-kevin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockbackground-kevin.png -------------------------------------------------------------------------------- /Clock/images/clockbackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockbackground.png -------------------------------------------------------------------------------- /Clock/images/clockface3-darkblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockface3-darkblue.png -------------------------------------------------------------------------------- /Clock/images/clockface3-darkgreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockface3-darkgreen.png -------------------------------------------------------------------------------- /Clock/images/clockface3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/clockface3.png -------------------------------------------------------------------------------- /Clock/images/hourhand-darkblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/hourhand-darkblue.png -------------------------------------------------------------------------------- /Clock/images/hourhand-darkgreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/hourhand-darkgreen.png -------------------------------------------------------------------------------- /Clock/images/hourhand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/hourhand.png -------------------------------------------------------------------------------- /Clock/images/minhand-darkblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/minhand-darkblue.png -------------------------------------------------------------------------------- /Clock/images/minhand-darkgreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/minhand-darkgreen.png -------------------------------------------------------------------------------- /Clock/images/minhand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/minhand.png -------------------------------------------------------------------------------- /Clock/images/sechand-darkblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/sechand-darkblue.png -------------------------------------------------------------------------------- /Clock/images/sechand-darkgreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/sechand-darkgreen.png -------------------------------------------------------------------------------- /Clock/images/sechand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/sechand.png -------------------------------------------------------------------------------- /Clock/images/slideshow/daniel-h-tong-1310255-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/slideshow/daniel-h-tong-1310255-unsplash.jpg -------------------------------------------------------------------------------- /Clock/images/slideshow/johannes-plenio-629984-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/slideshow/johannes-plenio-629984-unsplash.jpg -------------------------------------------------------------------------------- /Clock/images/slideshow/nasa-53888-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/slideshow/nasa-53888-unsplash.jpg -------------------------------------------------------------------------------- /Clock/images/slideshow/patrick-tomasso-1311143-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/slideshow/patrick-tomasso-1311143-unsplash.jpg -------------------------------------------------------------------------------- /Clock/images/slideshow/roman-bozhko-251398-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/slideshow/roman-bozhko-251398-unsplash.jpg -------------------------------------------------------------------------------- /Clock/images/slideshow/shot-by-cerqueira-1318576-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/slideshow/shot-by-cerqueira-1318576-unsplash.jpg -------------------------------------------------------------------------------- /Clock/images/squares1-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/squares1-green.png -------------------------------------------------------------------------------- /Clock/images/squares1-jean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/squares1-jean.png -------------------------------------------------------------------------------- /Clock/images/squares1-kevin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/squares1-kevin.png -------------------------------------------------------------------------------- /Clock/images/squares2-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/squares2-green.png -------------------------------------------------------------------------------- /Clock/images/squares2-jean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/squares2-jean.png -------------------------------------------------------------------------------- /Clock/images/squares2-kevin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/images/squares2-kevin.png -------------------------------------------------------------------------------- /Clock/markers/Readme.md: -------------------------------------------------------------------------------- 1 | # Custom markers 2 | 3 | This folder contains some sample map markers which are overlayed onto the 4 | radar maps as directed by your config file. 5 | 6 | markers.xcf is a gimp file containing several of the teardrop markers 7 | which I've made. 8 | 9 | Each image is 64x64 with the center of the image being placed on the location 10 | on the map. 11 | -------------------------------------------------------------------------------- /Clock/markers/markers.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/markers/markers.xcf -------------------------------------------------------------------------------- /Clock/markers/teardrop-dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/markers/teardrop-dot.png -------------------------------------------------------------------------------- /Clock/markers/teardrop-family.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/markers/teardrop-family.png -------------------------------------------------------------------------------- /Clock/markers/teardrop-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/markers/teardrop-home.png -------------------------------------------------------------------------------- /Clock/markers/teardrop-school.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/markers/teardrop-school.png -------------------------------------------------------------------------------- /Clock/markers/teardrop-work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/markers/teardrop-work.png -------------------------------------------------------------------------------- /Clock/markers/teardrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Clock/markers/teardrop.png -------------------------------------------------------------------------------- /Contributed/PiClock_neo-aeon-Clockface-FliegerB.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Contributed/PiClock_neo-aeon-Clockface-FliegerB.zip -------------------------------------------------------------------------------- /Contributed/PiClock_neo-aeon-ClockfaceGuide-GIMP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Contributed/PiClock_neo-aeon-ClockfaceGuide-GIMP.zip -------------------------------------------------------------------------------- /Contributed/Readme.md: -------------------------------------------------------------------------------- 1 | # Things submitted by various PiClock Makers 2 | 3 | @neo-aeon submitted some cool things 4 | 5 | * A great analog clock face PiClock_neo-aeon-Clockface-FliegerB.zip 6 | * A clock face and hands making guide as gimp files. 7 | 8 | ### Personal thanks for the contriubtions. 9 | -------------------------------------------------------------------------------- /Documentation/2015-06-11_10-36-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/2015-06-11_10-36-44.png -------------------------------------------------------------------------------- /Documentation/Digital Clock v1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/Digital Clock v1.jpg -------------------------------------------------------------------------------- /Documentation/Digital Clock v2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/Digital Clock v2.jpg -------------------------------------------------------------------------------- /Documentation/Hardware.md: -------------------------------------------------------------------------------- 1 | # PiClock Hardware Guide 2 | 3 | ## Introduction 4 | 5 | I'm going to assume you know how to connect your Raspberry Pi, Power supply, Monitor, 6 | keyboard/mouse and Wifi or Wired Ethernet. 7 | 8 | What follows is the details of various optional hardware you can add to your Raspi 9 | to add features or make your clock cooler. 10 | 11 | If you want to experiment and learn about the various hardware, and possibly breadboard 12 | them first, I've included some decent guides for that. *However, you can just skip to the 13 | picture showing the hookup for the PiClock.* 14 | 15 | ## Raspberry Pi Models 16 | 17 | This hardware guide directly supports the following 18 | 19 | * Raspsbery Pi Revision 2 Model B 20 | * Raspberry Pi Revision 2 Model B 21 | * Raspberry Pi Model B+ 22 | * Raspberry Pi 2 Model B 23 | 24 | Changes can be made, alternate pins (grounds/gpios) can be used to support 25 | other models, but this is left as an exercise for the reader. 26 | 27 | 28 | ## IR receiver (TSOP4838) 29 | 30 | There are many guides showing how to connect an IR receiver (and IR LEDs) to a Raspberry Pi. 31 | Here's one: http://www.raspberry-pi-geek.com/Archive/2014/03/Controlling-your-Pi-with-an-infrared-remote 32 | 33 | One thing to note is that most of these use GPIO18 (header pin 12). The Install instructions I've provided 34 | require the use of **GPIO3 (header pin 5)**. I've found this more convenient, usually sharing the connector 35 | with the DS18B20 temperature probe on GPIO4 (header pin 7). 36 | 37 | ``` 38 | Raspi Header Pin TSOP4838 Pin 39 | 3.3V Pin 1 Pin 2 40 | Gnd Pin 9 Pin 1 41 | GPIO3 Pin 5 Pin 3 42 | ``` 43 | ![PiClock Picture](https://raw.githubusercontent.com/n0bel/PiClock/master/Documentation/tsop4838.jpg) 44 | 45 | ## Inside Temperature ( DS18B20 ) 46 | 47 | There are many guides showing how to connect and check one or more DS18B20s to 48 | a Raspberry Pi. Here's one: http://www.modmypi.com/blog/ds18b20-one-wire-digital-temperature-sensor-and-the-raspberry-pi 49 | 50 | ``` 51 | Raspi Header Pin DS18B20 Pin 52 | 3.3V Pin 1 Pin 3 53 | Gnd Pin 9 Pin 1 54 | GPIO4 Pin 7 Pin 2 55 | ``` 56 | 57 | ![PiClock Picture](https://raw.githubusercontent.com/n0bel/PiClock/master/Documentation/ds18b20.jpg) 58 | 59 | 60 | ## WS2818b RGB LED AmbiLight strip 61 | 62 | A good background guide about how WS2818b connects to the Raspberry Pi can be found here: 63 | https://learn.adafruit.com/neopixels-on-raspberry-pi/overview 64 | 65 | You might be tempted to connect the LED strip power to the 5V header pin of the Pi -- just don't! 66 | That pin can't pass enough current. With all the lights on full you may need an extra 2A to 67 | power a 30 LED string (NeoPixels for example come in 30, 60 and 144 LEDs per meter), so size 68 | your power supply accordingly. 69 | 70 | Everyone seems to recommend a level shift (3.3V to 5V) to drive the LEDs. I've found this to 71 | be unnecessary. It also seems that Adafruit recommends a 1000uF cap on the power supply, with 72 | the dubious explaination that it protects the LEDs from inrush surges. Again I don't botther. 73 | Meh... Your milage may vary. The data pin of the WS2818b string should be connected 74 | to GPIO18, header pin 12. Note the markings on the LED strip since they all are not pinned 75 | the same. 76 | 77 | 78 | ![PiClock Picture](https://raw.githubusercontent.com/n0bel/PiClock/master/Documentation/NeoPixel.jpg) 79 | 80 | ## GPIO Buttons 81 | 82 | Up to 3 simple push button switches come preconfigured in the software. The switches are 83 | wired simply to connect a gpio pin to ground when pushed. The following line 84 | in startup.sh configure their function, and which GPIO they are located on. 85 | ``` 86 | sudo Button/gpio-keys 23:KEY_SPACE 24:KEY_F2 25:KEY_UP & 87 | ``` 88 | * GPIO23 (header pin 16) is mapped to a space (which flips pages on the clock. 89 | * GPIO24 (header pin 18) is mapped to F2 (which toggles the NOAA stream) 90 | * GPIO25 (header pin 22) is mapped to UP (which does nothing yet) 91 | * A convinient ground is on header pin 20. 92 | 93 | ![PiClock Picture](https://raw.githubusercontent.com/n0bel/PiClock/master/Documentation/gpiobuttons.jpg) 94 | 95 | 96 | ## Schematic of all connections 97 | 98 | For those that want to work from a schematic, I threw together a simple one 99 | 100 | ![PiClock Picture](https://raw.githubusercontent.com/n0bel/PiClock/master/Documentation/Hardware_Schematic.png) 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Documentation/Hardware_Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/Hardware_Schematic.pdf -------------------------------------------------------------------------------- /Documentation/Hardware_Schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/Hardware_Schematic.png -------------------------------------------------------------------------------- /Documentation/Install-Clock-Only.md: -------------------------------------------------------------------------------- 1 | # Install Instructions for PiClock (Clock Only) 2 | 3 | This version of the instructions is for setting up just the clock 4 | itself, ignoring all the other options. It also assumes you have 5 | some OS already setup. So this is useful for setting up the 6 | clock on a desktop OS. 7 | 8 | # Prerequisites 9 | 10 | The minium requirements for a PiClock is pretty simple 11 | * Python 2.7+ (but not 3) 12 | * Python Qt4, known as PyQt4 13 | * git (as an alternative to git, you can pull the zip file from git hub 14 | (download button on the right side of the github project) then unzip it 15 | onto your system ) 16 | 17 | Theses are available under Windows, Linux, and OSX OS's. 18 | 19 | How to get these installed on your choice of system I'll leave 20 | as an excersise for the reader. 21 | 22 | ### Get the PiClock software 23 | ``` 24 | git clone https://github.com/n0bel/PiClock.git 25 | ``` 26 | Alternatively, you can download a zip file of the github project. 27 | 28 | https://github.com/n0bel/PiClock/archive/master.zip, then unzip it. 29 | 30 | 31 | ### Configure the PiClock api keys 32 | 33 | The first is to set API keys for DarkSky and Google Maps. 34 | These are both free, unless you have large volume. 35 | The PiClock usage is well below the maximums imposed by the no cost api keys. 36 | 37 | #### DarkSky api keys 38 | 39 | DarkSky api keys are created at this link: 40 | https://darksky.net/dev 41 | 42 | #### Google Maps API key 43 | 44 | A Google Maps api key is _required_. (Requires credit card which won't be 45 | charged unless usage is great.) 46 | 47 | An intro to Google static maps api keys, and a link to creating your account and ApiKeys: 48 | https://developers.google.com/maps/documentation/maps-static/intro 49 | You'll require a google user and password. It'll also require a credit card. 50 | The credit card should not be charged, because my reading of https://cloud.google.com/maps-platform/pricing/sheet/ the $200.00 credit will 51 | apply, and your charges incurred will be for 31 map pulls per month will be 52 | $0.62 , if you reboot daily. 53 | You'll be required to create a "project" (maybe PiClock for a project name?) 54 | You need to then activate the key. 55 | 56 | _Protect your API keys._ You'd be surprised how many pastebin's are out 57 | there with valid API keys, because of people not being careful. If you post 58 | your keys somewhere, your usage will skyrocket, and your bill as well. Google 59 | has the ability to add referer, device and ip requirements on your api key. It 60 | can also allow you to limit an api key to specific applications only (static-maps) 61 | in this case. Also you might consider disabling all the other APIs on your 62 | project dashboard. Under the Billing section of things you can set up budgets 63 | and alerts. (Set to like $1.00) 64 | 65 | 66 | Now that you have your api keys... 67 | 68 | ``` 69 | cd PiClock 70 | cd Clock 71 | cp ApiKeys-example.py ApiKeys.py 72 | [use your favorite editor] ApiKeys.py 73 | ``` 74 | Put your api keys in the file as indicated 75 | ``` 76 | #change this to your API keys 77 | # DarkSky API key 78 | dsapi = 'YOUR DARKSKY API KEY' 79 | # Google Maps API key 80 | googleapi = 'YOUR GOOGLE API KEY' 81 | ``` 82 | 83 | ### Configure your PiClock 84 | here's were you tell PiClock where your weather should come from, and the 85 | radar map centers and markers. 86 | 87 | ``` 88 | cd PiClock 89 | cd Clock 90 | cp Config-Example.py Config.py (copy on windows) 91 | [use your favorite editor] Config.py 92 | ``` 93 | 94 | This file is a python script, subject to python rules and syntax. 95 | The configuration is a set of variables, objects and arrays, 96 | set up in python syntax. The positioning of the {} and () and ',' 97 | are not arbitrary. If you're not familiar with python, use extra 98 | care not to disturb the format while changing the data. 99 | 100 | The first thing is to change the Latitudes and Longitudes you see to yours. 101 | They occur in several places. The first one in the file is where your weather 102 | forecast comes from. The others are where your radar images are centered 103 | and where the markers appear on those images. Markers are those little red 104 | location pointers. 105 | 106 | ### Run it! 107 | 108 | ``` 109 | cd PiClock 110 | python PyQtPiClock.py 111 | ``` 112 | After a few seconds, your screen should be covered by the PiClock YAY! 113 | 114 | There may be some output on the terminal screen as it executes. 115 | If everything works, it can be ignored. If for some reason the clock 116 | doesn't work, or maps are missing, etc the output may give a reason 117 | or reasons, which usually reference something to do with the config 118 | file (Config.py) 119 | 120 | ### First Use 121 | 122 | * The space bar or right or left arrows will change the page. 123 | * F2 will start and stop the NOAA weather radio stream 124 | * F4 will close the clock 125 | 126 | 127 | ### Updating to newer/updated versions 128 | Since we pulled the software from github originally, it can be updated 129 | using git and github. 130 | ``` 131 | cd PiClock 132 | git pull 133 | python update.py 134 | ``` 135 | This will automatically update any part(s) of the software that has changed. 136 | The update.py program will then convert any config files as needed. 137 | -------------------------------------------------------------------------------- /Documentation/Install-Jessie.md: -------------------------------------------------------------------------------- 1 | # Install Instructions for PiClock 2 | ## For Raspbian Jessie 3 | 4 | PiClock and this install guide are based on Raspian Jessie 5 | last released on https://downloads.raspberrypi.org/raspbian/images/raspbian-2017-07-05/ 6 | It will work with many raspbian versions, but you may have to add more packages, 7 | etc. That exercise is left for the reader. 8 | 9 | What follows is a step by step guide. If you start with a new clean raspbian 10 | image, it should just work. I'm assuming that you already know how to hook 11 | up your Raspi, monitor, and keyboard/mouse. If not, please do a web search 12 | regarding setting up the basic hardware for your Raspi. 13 | 14 | ### Download Raspbian Jessie and put it on an SD Card 15 | 16 | The image and instructions for doing this are on the following page: 17 | https://www.raspberrypi.org/downloads/ 18 | 19 | ### First boot and configure 20 | A keyboard and mouse are really handy at this point. 21 | When you first boot your Pi, you'll be presented with the desktop. 22 | Navigate to Menu->Preferences->Raspberry Pi Configuration. 23 | Just change the Items below. 24 | - General Tab 25 | - Change User Password -- this will set the password for the use pi, 26 | for ssh logins. 27 | - Hostname: (Maybe set this to PiClock?) 28 | - Boot: To Desktop 29 | - Auto Login: Checked 30 | - Underscan: (Initally leave as default, but if your monitor has extra black area on the border, or bleeds off the edge, then change this) 31 | - Interfaces 32 | - 1-Wire Enable (for the inside temperature, DS18B20 if you're using it) 33 | - Internationalization Tab 34 | - Set Locale. 35 | - Set Language -- if you set language and country here, the date will automaticly be in your language 36 | -- other settings in Config.py (described later) control the language of the weather data 37 | - Set Country 38 | - Character Set: UTF-8 39 | - Set Timezone. 40 | - You'll want this to be correct, or the clock will be wrong. 41 | - Set Keyboard 42 | - Generally not needed, but good to check if you like the default 43 | - Set WiFi Country (may not always show up) 44 | 45 | Finish and let it reboot. 46 | 47 | I've found that sometimes on reboot, Jessie doesn't go back to desktop mode. 48 | If this is the case, 49 | ``` 50 | sudo raspi-config 51 | ``` 52 | and change the boot option to Desktop/Auto-login 53 | 54 | ### editing config.txt 55 | 56 | Log into your Pi, (either on the screen or via ssh) 57 | 58 | use nano to edit the boot config file 59 | ``` 60 | sudo nano /boot/config.txt 61 | ``` 62 | Be sure the lines 63 | ``` 64 | dtoverlay=lirc-rpi,gpio_in_pin=3,gpio_out_pin=2 65 | dtoverlay=w1-gpio,gpiopin=4 66 | ``` 67 | are in there somewhere, and occur only once. 68 | The default config has lirc-rpi commented out (# in front), don't forget to remove the # 69 | Also add the pin arguments just as shown above, if they are not already there. 70 | 71 | You're free to change the pins, but of course the hardware guide will need to 72 | be adjusted to match. 73 | 74 | use nano to edit the modules file 75 | ``` 76 | sudo nano /etc/modules 77 | ``` 78 | Be sure the lines 79 | ``` 80 | lirc_rpi gpio_in_pin=3 gpio_out_pin=2 81 | w1-gpio 82 | ``` 83 | are in there somewhere, and only occur once. 84 | 85 | reboot 86 | ``` 87 | sudo reboot 88 | ``` 89 | 90 | ### Get connected to the internet 91 | 92 | Either connect to your wired network, or setup wifi and verify you have 93 | internet access from the Pi 94 | 95 | ``` 96 | ping github.com 97 | ``` 98 | (remember ctrl-c aborts programs, like breaking out of ping, which will 99 | go on forever) 100 | 101 | ### Get all the software that PiClock needs. 102 | 103 | Become super user! (root) (trumpets play in the background) (ok, maybe 104 | just in my head) 105 | ``` 106 | sudo su - 107 | ``` 108 | update the repository 109 | ``` 110 | apt-get update 111 | ``` 112 | then get qt4 for python 113 | ``` 114 | apt-get install python-qt4 115 | ``` 116 | you may need to confirm some things, like: 117 | After this operation, 44.4 MB of additional disk space will be used. 118 | Do you want to continue [Y/n]? y 119 | Go ahead, say yes 120 | 121 | then get ws281x driver for python (optional for the NeoPixel LED Driver) 122 | ``` 123 | pip install rpi_ws281x 124 | ``` 125 | Someversions of Raspbian need python-dev to be installed as well, before 126 | rpi-ws281x can be installed. If the prevous command fails reporting 127 | a missing include file, then do this: 128 | ``` 129 | apt-get install python-dev 130 | ``` 131 | Then try the pip command again. 132 | 133 | then install more needed python libraries 134 | ``` 135 | pip install python-dateutil --upgrade 136 | pip install tzlocal --upgrade 137 | pip install python-metar --upgrade 138 | ``` 139 | 140 | then get unclutter (disables the mouse pointer when there's no activity) 141 | ``` 142 | apt-get install unclutter 143 | ``` 144 | 145 | ### Get the DS18B20 Temperature driver for Python (optional) 146 | 147 | (you must still be root [super user]) 148 | ``` 149 | git clone https://github.com/timofurrer/w1thermsensor.git && cd w1thermsensor 150 | python setup.py install 151 | ``` 152 | 153 | ### Get Lirc driver for IR remote (optional) 154 | 155 | (you must still be root [super user]) 156 | ``` 157 | apt-get install lirc 158 | ``` 159 | 160 | use nano to edit lirc hardware file 161 | ``` 162 | sudo nano /etc/lirc/hardware.conf 163 | ``` 164 | Be sure the LIRCD_ARGS line appears as follows 165 | ``` 166 | LIRCD_ARGS="--uinput" 167 | ``` 168 | 169 | Be sure the DRIVER line appears as follows 170 | ``` 171 | DRIVER="default" 172 | ``` 173 | 174 | Be sure the DEVICE line appears as follows 175 | ``` 176 | DEVICE="/dev/lirc0" 177 | ``` 178 | 179 | Be sure the MODULES line appears as follows 180 | ``` 181 | MODULES="lirc_rpi" 182 | ``` 183 | 184 | ### Get mpg123 (optional to play NOAA weather radio streams) 185 | 186 | (you must still be root [super user]) 187 | ``` 188 | apt-get install mpg123 189 | ``` 190 | 191 | ### reboot 192 | To get some things running, and ensure the final config is right, we'll do 193 | a reboot 194 | ``` 195 | reboot 196 | ``` 197 | 198 | ### Get the PiClock software 199 | Log into your Pi, (either on the screen or via ssh) (NOT as root) 200 | You'll be in the home directory of the user pi (/home/pi) by default, 201 | and this is where we want to be. 202 | ``` 203 | git clone https://github.com/n0bel/PiClock.git 204 | ``` 205 | Once that is done, you'll have a new directory called PiClock 206 | A few commands are needed if you intend to use gpio buttons 207 | and the gpio-keys driver to compile it for the latest Raspbian: 208 | ``` 209 | cd PiClock/Button 210 | make gpio-keys 211 | cd ../.. 212 | ``` 213 | 214 | ### Set up Lirc (IR Remote) 215 | If you're using the recommended IR Key Fob, 216 | https://www.google.com/search?q=Mini+Universal+Infrared+IR+TV+Set+Remote+Control+Keychain 217 | you can copy the lircd.conf file included in the distribution as follows: 218 | ``` 219 | sudo cp IR/lircd.conf /etc/lirc/ 220 | ``` 221 | If you're using something else, you'll need to use irrecord, or load a remote file 222 | as found on http://lirc.org/ 223 | 224 | The software expects 7 keys. KEY_F1, KEY_F2, KEY_F3, KEY_UP, KEY_DOWN, KEY_RIGHT 225 | and KEY_LEFT. Lirc takes these keys and injects them into linix as if they 226 | were typed from a keyboard. PyQPiClock.py then simply looks for normal keyboard 227 | events. Therefore of course, if you have a usb keyboard attached, those keys 228 | work too. On the key fob remote, F1 is power, F2 is mute and F3 is AV/TV. 229 | 230 | You should (must) verify your IR codes. I've included a program called IRCodes.pl 231 | which will verify that your lircd.conf is setup correctly. 232 | If you've rebooted after installing lircd.conf, you'll have to stop lirc first: 233 | ``` 234 | sudo service lirc stop 235 | ``` 236 | Then use the IRCodes.pl program as follows: 237 | ``` 238 | perl IR/IRCodes.pl 239 | ``` 240 | Yes, I reverted to perl.. I may redo it in Python one day. 241 | 242 | If you're using the recommended key fob remote, they come randomly programmed from 243 | the supplier. To program them you press and hold the mute button (the middle one) 244 | while watching the screen scroll through codes. 245 | When the screen shows 246 | ``` 247 | ************ KEY_F2 248 | ``` 249 | STOP! then try the other keys, be sure they all report KEY_UP, KEY_DOWN correctly. 250 | If not press and hold the mute button again, waiting for the asterisks and KEY_F2, 251 | then STOP again, try the other keys. Repeat the process until you have all the 252 | keys working. 253 | 254 | Ctrl-C to abort perl. 255 | 256 | then reboot 257 | ``` 258 | sudo reboot 259 | ``` 260 | 261 | 262 | ### Configure the PiClock api keys 263 | 264 | The first is to set API keys for DarkSky and Google Maps. 265 | These are both free, unless you have large volume. 266 | The PiClock usage is well below the maximums imposed by the no cost api keys. 267 | 268 | #### DarkSky api keys 269 | 270 | DarkSky api keys are created at this link: 271 | https://darksky.net/dev 272 | 273 | #### Google Maps API key 274 | 275 | A Google Maps api key is _required_. (Requires credit card which won't be 276 | charged unless usage is great.) 277 | 278 | An intro to Google static maps api keys, and a link to creating your account and ApiKeys: 279 | https://developers.google.com/maps/documentation/maps-static/intro 280 | You'll require a google user and password. It'll also require a credit card. 281 | The credit card should not be charged, because my reading of https://cloud.google.com/maps-platform/pricing/sheet/ the $200.00 credit will 282 | apply, and your charges incurred will be for 31 map pulls per month will be 283 | $0.62 , if you reboot daily. 284 | You'll be required to create a "project" (maybe PiClock for a project name?) 285 | You need to then activate the key. 286 | 287 | _Protect your API keys._ You'd be surprised how many pastebin's are out 288 | there with valid API keys, because of people not being careful. If you post 289 | your keys somewhere, your usage will skyrocket, and your bill as well. Google 290 | has the ability to add referer, device and ip requirements on your api key. It 291 | can also allow you to limit an api key to specific applications only (static-maps) 292 | in this case. Also you might consider disabling all the other APIs on your 293 | project dashboard. Under the Billing section of things you can set up budgets 294 | and alerts. (Set to like $1.00) 295 | 296 | 297 | Now that you have your api keys... 298 | 299 | ``` 300 | cd PiClock 301 | cd Clock 302 | cp ApiKeys-example.py ApiKeys.py 303 | nano ApiKeys.py 304 | ``` 305 | Put your api keys in the file as indicated 306 | ``` 307 | #change this to your API keys 308 | # DarkSky API key 309 | dsapi = 'YOUR DARKSKY API KEY' 310 | # Google Maps API key 311 | googleapi = 'YOUR GOOGLE API KEY' 312 | ``` 313 | 314 | ### Configure your PiClock 315 | here's were you tell PiClock where your weather should come from, and the 316 | radar map centers and markers. 317 | 318 | ``` 319 | cd PiClock 320 | cd Clock 321 | cp Config-Example.py Config.py 322 | nano Config.py 323 | ``` 324 | 325 | This file is a python script, subject to python rules and syntax. 326 | The configuration is a set of variables, objects and arrays, 327 | set up in python syntax. The positioning of the {} and () and ',' 328 | are not arbitrary. If you're not familiar with python, use extra 329 | care not to disturb the format while changing the data. 330 | 331 | The first thing is to change the primary_coordinates to yours. That is really 332 | all that is manditory. Further customization of the radar maps can be done in 333 | the Radar section. There you can customize where your radar images are centered 334 | and where the markers appear on those images. Markers are those little red 335 | location pointers. Radar1 and 2 show on the first page, and 3 and 4 show on the 336 | second page of the display (here's a post of about that: 337 | https://www.facebook.com/permalink.php?story_fbid=1371576642857593&id=946361588712436&substory_index=0 ) 338 | 339 | The second thing to change is your NOAA weather radio stream url. You can 340 | find it here: http://noaaweatherradio.org/ They don't put the .mp3 urls 341 | where they are easily accessable, so you need to use your browser to "View Page Source" 342 | in order to find the proper .mp3 url. 343 | 344 | At this point, I'd not recommend many other changes until you have tested 345 | and gotten it running. 346 | 347 | ### Run it! 348 | You'll need to be on the desktop, in a terminal program. 349 | 350 | ``` 351 | cd PiClock 352 | sh startup.sh -n -s 353 | ``` 354 | Your screen should be covered by the PiClock YAY! 355 | 356 | There will be some output on the terminal screen as startup.sh executes. 357 | If everything works, it can be ignored. If for some reason the clock 358 | doesn't work, or maps are missing, etc the output may give a reason 359 | or reasons, which usually reference something to do with the config 360 | file (Config.py) 361 | 362 | ### Logs 363 | The -s option causes no log files to be created, but 364 | instead logs to your terminal screen. If -s is omitted, logs are 365 | created in PiClock/Clock as PyQtPiClock.[1-7].log, which can also help 366 | you find issues. -s is normally omitted when started from the desktop icon 367 | or from crontab. Logs are then created for debugging auto starts. 368 | 369 | ### First Use 370 | 371 | * The space bar or right or left arrows will change the page. 372 | * F2 will start and stop the NOAA weather radio stream 373 | * F4 will close the clock 374 | 375 | If you're using the temperature feature AND you have multiple temperature sensors, 376 | you'll see the clock display: 000000283872:74.6 00000023489:65.4 or something similar. 377 | Note the numbers exactly. Use F4 to stop the clock, 378 | then.. 379 | ``` 380 | nano Temperature/TempNames.py 381 | ``` 382 | Give each number a name, like is shown in the examples in that file 383 | 384 | ### setting the clock to auto start 385 | At this point the clock will only start when you manually start it, as 386 | described in the Run It section. 387 | 388 | Use only one autostart method. 389 | ## Autostart Method 1 390 | (NOT as root) 391 | ``` 392 | cd PiClock 393 | chmod +x PiClock.desktop 394 | ln PiClock.desktop ~/Desktop 395 | mkdir ~/.config/autostart 396 | ln PiClock.desktop ~/.config/autostart 397 | ``` 398 | This puts the a PiClock icon on your desktop. It also runs it when 399 | the desktop starts. 400 | 401 | ## Autostart Method 2 402 | To have it auto start on boot we need to do one more thing, edit the 403 | crontab file as follows: (it will automatically start nano) (NOT as root) 404 | ``` 405 | crontab -e 406 | ``` 407 | and add the following line: 408 | ``` 409 | @reboot sh /home/pi/PiClock/startup.sh 410 | ``` 411 | save the file 412 | and reboot to test 413 | ``` 414 | sudo reboot 415 | ``` 416 | 417 | ## Some notes about startup.sh 418 | startup.sh has a few options: 419 | * -n or --no-delay Don't delay on starting the clock right away (default is 45 seconds delay) 420 | * -d X or --delay X Delay X seconds before starting the clock 421 | * -m X or --message-delay X Delay X seconds while displaying a message on the desktop 422 | 423 | Startup also looks at the various optional PiClock items (Buttons, Temperature, NeoPixel, etc) 424 | and only starts those things that are configured to run. It also checks if they are already 425 | running, and refrains from starting them again if they are. 426 | 427 | ### Switching skins at certain times of the day 428 | This is optional, but if its just too bright at night, a switcher script will kill and restart 429 | PyQtPiClock with an alternate config. 430 | 431 | First you need to set up an alternate config. Config.py is the normal name, so perhaps Config-Night.py 432 | might be appropriate. For a dimmer display use Config-Example-Bedside.py as a guide. 433 | 434 | Now we'll tell our friend cron to run the switcher script (switcher.sh) on day/night cycles. 435 | Run the cron editor: (should *not* be roor) 436 | ``` 437 | crontab -e 438 | ``` 439 | Add lines similar to this: 440 | ``` 441 | 0 8 * * * sh /home/pi/PiClock/switcher.sh Config 442 | 0 21 * * * sh /home/pi/PiClock/switcher.sh Config-Night 443 | ``` 444 | The 8 there means 8am, to switch to the normal config, and the 21 means switch to Config-Night at 9pm. 445 | More info on crontab can be found here: https://en.wikipedia.org/wiki/Cron 446 | 447 | ### Setting the Pi to auto reboot every day 448 | This is optional but some may want their PiClock to reboot every day. I do this with mine, 449 | but it is probably not needed. 450 | ``` 451 | sudo crontab -e 452 | ``` 453 | add the following line 454 | ``` 455 | 22 3 * * * /sbin/reboot 456 | ``` 457 | save the file 458 | 459 | This sets the reboot to occur at 3:22am every day. Adjust as needed. 460 | 461 | ### Updating to newer/updated versions 462 | Since we pulled the software from github originally, it can be updated 463 | using git and github. 464 | ``` 465 | cd PiClock 466 | git pull 467 | python update.py 468 | ``` 469 | This will automatically update any part(s) of the software that has changed. 470 | The update.py program will then convert any config files as needed. 471 | 472 | You'll want to reboot after the update. 473 | 474 | Note: If you get errors because you've made changes to the base code you might need 475 | ``` 476 | git reset --hard 477 | ``` 478 | Backup your changes first! 479 | (This won't bother your Config.py nor ApiKeys.py because they are not tracked in git. 480 | 481 | Also, if you're using gpio-keys, you may need to remake it: 482 | ``` 483 | cd PiClock/Buttons 484 | rm gpio-keys 485 | make gpio-keys 486 | ``` 487 | -------------------------------------------------------------------------------- /Documentation/Install.md: -------------------------------------------------------------------------------- 1 | # Install Instructions for PiClock 2 | ## For Raspbian Stretch 3 | 4 | PiClock and this install guide are based on Raspian Stretch downloaded from 5 | https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/ I suggest using 6 | "Raspbian Stretch with desktop" It will work with many raspbian versions, 7 | but you may have to add more packages, etc. That exercise is left for the reader. 8 | 9 | What follows is a step by step guide. If you start with a new clean raspbian 10 | image, it should just work. I'm assuming that you already know how to hook 11 | up your Raspi, monitor, and keyboard/mouse. If not, please do a web search 12 | regarding setting up the basic hardware for your Raspi. 13 | 14 | ### Download Raspbian Stretch and put it on an SD Card 15 | 16 | Download the zip file, and unzip it. You'll have a .img file. You'll need 17 | an Imaging program like Win32 Disk Imager http://sourceforge.net/projects/win32diskimager/ 18 | 19 | ![Win32 Disk Imager](https://cdn.shopify.com/s/files/1/0176/3274/files/6_6153a773-ecc0-4ba5-9b01-d2aa7780cc8f_1024x1024.png "Win32 Disk Imager") 20 | 21 | Now, insert your SD card into your laptop/computer and browse to your image file. 22 | 23 | ![Choose Image and SD Card](https://cdn.shopify.com/s/files/1/0176/3274/files/7_1024x1024.png "Choose Image and SD Card") 24 | 25 | **BEFORE YOU HIT WRITE - Please make sure that you have selected the correct device. 26 | Win32 will pick up any removable media including SSD's. The last thing you want to 27 | do is overwrite your computer's hard drive!** 28 | 29 | When you're happy that you have the **correct image**, and **correct device**, hit write. 30 | 31 | You'll get a warning message to confirm that you're happy to proceed. 32 | Hit yes, and the image will burn to your card. 33 | 34 | 35 | ### First boot and configure 36 | A keyboard and mouse are really handy at this point. 37 | When you first boot your Pi, you'll be presented with the desktop. 38 | Following this there will be several prompts to set things up, follow 39 | those prompts and set things as they make sense for you. Of course 40 | setting the proper timezone for a clock is key. 41 | 42 | Eventually the Pi will reboot, and you'll be back to the desktop. 43 | We need to configure a few more things. 44 | 45 | Navigate to Menu->Preferences->Raspberry Pi Configuration. 46 | Just change the Items below. 47 | - System Tab 48 | - Hostname: (Maybe set this to PiClock?) 49 | - Boot: To Desktop 50 | - Auto Login: Checked 51 | - Overscan: (Initally leave as default, but if your monitor has extra 52 | black area on the border, or bleeds off the edge, then change this) 53 | - Interfaces 54 | - 1-Wire Enable (for the inside temperature, DS18B20 if you're using it) 55 | - SSH is handy (if you'd like to connect to your clock from another computer) 56 | - VNC can be handy (same reason as ssh) 57 | 58 | 59 | Click ok, and allow it to reboot. 60 | 61 | ### editing config.txt 62 | 63 | (Only required if you will be using IR Remote control or DS18B20 temperature 64 | sensors) 65 | Log into your Pi, (either on the screen or via ssh) 66 | 67 | use nano to edit the boot config file 68 | ``` 69 | sudo nano /boot/config.txt 70 | ``` 71 | Be sure the lines 72 | ``` 73 | dtoverlay=lirc-rpi,gpio_in_pin=3,gpio_out_pin=2 74 | dtoverlay=w1-gpio,gpiopin=4 75 | ``` 76 | are in there somewhere, and occur only once. 77 | The default config has lirc-rpi commented out (# in front), don't forget to remove the # 78 | Also add the pin arguments just as shown above, if they are not already there. 79 | 80 | You're free to change the pins, but of course the hardware guide will need to 81 | be adjusted to match. 82 | 83 | use nano to edit the modules file 84 | ``` 85 | sudo nano /etc/modules 86 | ``` 87 | Be sure the lines 88 | ``` 89 | lirc_rpi gpio_in_pin=3 gpio_out_pin=2 90 | w1-gpio 91 | ``` 92 | are in there somewhere, and only occur once. 93 | 94 | reboot 95 | ``` 96 | sudo reboot 97 | ``` 98 | 99 | ### Get connected to the internet 100 | 101 | Verify you have internet access from the Pi 102 | 103 | ``` 104 | ping github.com 105 | ``` 106 | (remember ctrl-c aborts programs, like breaking out of ping, which will 107 | go on forever) 108 | 109 | ### Get all the software that PiClock needs. 110 | 111 | Become super user! (root) (trumpets play in the background) (ok, maybe 112 | just in my head) 113 | ``` 114 | sudo su - 115 | ``` 116 | update the repository 117 | ``` 118 | apt-get update 119 | ``` 120 | then get qt4 for python 121 | ``` 122 | apt-get install python-qt4 123 | ``` 124 | you may need to confirm some things, like: 125 | After this operation, 59.5 MB of additional disk space will be used. 126 | Do you want to continue [Y/n]? y 127 | Go ahead, say yes 128 | 129 | then get ws281x driver for python (optional for the NeoPixel LED Driver) 130 | ``` 131 | pip install rpi_ws281x 132 | ``` 133 | Someversions of Raspbian need python-dev to be installed as well, before 134 | rpi-ws281x can be installed. If the prevous command fails reporting 135 | a missing include file, then do this: 136 | ``` 137 | apt-get install python-dev 138 | ``` 139 | Then try the pip command again. 140 | 141 | then install more needed python libraries 142 | ``` 143 | pip install python-dateutil --upgrade 144 | pip install tzlocal --upgrade 145 | pip install python-metar --upgrade 146 | ``` 147 | 148 | then get unclutter (disables the mouse pointer when there's no activity) 149 | ``` 150 | apt-get install unclutter 151 | ``` 152 | 153 | ### Get the DS18B20 Temperature driver for Python (optional) 154 | 155 | (you must still be root [super user]) 156 | ``` 157 | git clone https://github.com/timofurrer/w1thermsensor.git && cd w1thermsensor 158 | python setup.py install 159 | ``` 160 | 161 | ### Get Lirc driver for IR remote (optional) 162 | 163 | (you must still be root [super user]) 164 | ``` 165 | apt-get install lirc 166 | ``` 167 | 168 | use nano to edit lirc options file 169 | ``` 170 | sudo nano /etc/lirc/lirc_options.conf 171 | ``` 172 | Be sure the uinput line appears as follows 173 | ``` 174 | uinput = True 175 | ``` 176 | 177 | Be sure the driver line appears as follows 178 | ``` 179 | driver = default 180 | 181 | ``` 182 | 183 | ### Get mpg123 (optional to play NOAA weather radio streams) 184 | 185 | (you must still be root [super user]) 186 | ``` 187 | apt-get install mpg123 188 | ``` 189 | 190 | ### reboot 191 | To get some things running, and ensure the final config is right, we'll do 192 | a reboot 193 | ``` 194 | reboot 195 | ``` 196 | 197 | ### Get the PiClock software 198 | Log into your Pi, (either on the screen or via ssh) (NOT as root) 199 | You'll be in the home directory of the user pi (/home/pi) by default, 200 | and this is where we want to be. Note that the following command while 201 | itself not being case sensitive, further operation of PiClock may be 202 | affected if the upper and lower case of the command is not followed. 203 | ``` 204 | git clone https://github.com/n0bel/PiClock.git 205 | ``` 206 | (Optional for GPIO keys) 207 | Once that is done, you'll have a new directory called PiClock 208 | A few commands are needed if you intend to use gpio buttons 209 | and the gpio-keys driver to compile it for the latest Raspbian: 210 | ``` 211 | cd PiClock/Button 212 | make gpio-keys 213 | cd ../.. 214 | ``` 215 | 216 | ### Set up Lirc (IR Remote) 217 | 218 | If you're using the recommended IR Key Fob, 219 | https://www.google.com/search?q=Mini+Universal+Infrared+IR+TV+Set+Remote+Control+Keychain 220 | you can copy the lircd.conf file included in the distribution as follows: 221 | ``` 222 | sudo cp IR/lircd.conf /etc/lirc/lircd.conf.d/ 223 | ``` 224 | If you're using something else, you'll need to use irrecord, or load a remote file 225 | as found on http://lirc.org/ 226 | 227 | The software expects 7 keys. KEY_F1, KEY_F2, KEY_F3, KEY_UP, KEY_DOWN, KEY_RIGHT 228 | and KEY_LEFT. Lirc takes these keys and injects them into linix as if they 229 | were typed from a keyboard. PyQPiClock.py then simply looks for normal keyboard 230 | events. Therefore of course, if you have a usb keyboard attached, those keys 231 | work too. On the key fob remote, F1 is power, F2 is mute and F3 is AV/TV. 232 | 233 | You should (must) verify your IR codes. I've included a program called IRCodes.pl 234 | which will verify that your lircd.conf is setup correctly. 235 | If you've rebooted after installing lircd.conf, you'll have to stop lirc first: 236 | ``` 237 | sudo service lirc stop 238 | ``` 239 | Then use the IRCodes.pl program as follows: 240 | ``` 241 | perl IR/IRCodes.pl 242 | ``` 243 | Yes, I reverted to perl.. I may redo it in Python one day. 244 | 245 | If you're using the recommended key fob remote, they come randomly programmed from 246 | the supplier. To program them you press and hold the mute button (the middle one) 247 | while watching the screen scroll through codes. 248 | When the screen shows 249 | ``` 250 | ************ KEY_F2 251 | ``` 252 | STOP! then try the other keys, be sure they all report KEY_UP, KEY_DOWN correctly. 253 | If not press and hold the mute button again, waiting for the asterisks and KEY_F2, 254 | then STOP again, try the other keys. Repeat the process until you have all the 255 | keys working. 256 | 257 | Ctrl-C to abort perl. 258 | 259 | then reboot 260 | ``` 261 | sudo reboot 262 | ``` 263 | 264 | 265 | ### Configure the PiClock api keys 266 | 267 | We need to set API keys for DarkSky and Mapbox or Google Maps. 268 | These are both unless you have large volume. 269 | The PiClock usage is well below the maximums imposed by the no cost api keys. 270 | 271 | #### DarkSky api keys 272 | 273 | DarkSky api keys are created at this link: 274 | https://darksky.net/dev 275 | 276 | #### Map API Key 277 | 278 | You have your choice of Mapbox or Google Maps to get your underlying maps from. 279 | You only need one or the other (mbapi or googleapi) 280 | 281 | #### Google Maps API key 282 | 283 | A Google Maps api key is required to use Google Maps. 284 | (Requires credit card which won't be charged unless usage is great.) 285 | 286 | An intro to Google static maps api keys, and a link to creating your account and ApiKeys: 287 | https://developers.google.com/maps/documentation/maps-static/intro 288 | You'll require a google user and password. It'll also require a credit card. 289 | The credit card should not be charged, because my reading of 290 | https://cloud.google.com/maps-platform/pricing/sheet/ the $200.00 credit will 291 | apply, and your charges incurred will be for 31 map pulls per month will be 292 | $0.62 , if you reboot daily. 293 | You'll be required to create a "project" (maybe PiClock for a project name?) 294 | You need to then activate the key. 295 | 296 | _Protect your API keys._ You'd be surprised how many pastebin's are out 297 | there with valid API keys, because of people not being careful. _If you post 298 | your keys somewhere, your usage will skyrocket, and your bill as well._ Google 299 | has the ability to add referer, device and ip requirements on your api key. It 300 | can also allow you to limit an api key to specific applications only (static-maps) 301 | in this case. Also you might consider disabling all the other APIs on your 302 | project dashboard. Under the Billing section of things you can set up budgets 303 | and alerts. (Set to like $1.00) 304 | 305 | #### Mapbox api keys 306 | 307 | Mapbox api keys (access tokens) are created by signing up at this link: 308 | 309 | https://www.mapbox.com/signup/ 310 | 311 | 312 | 313 | Now that you have your api keys... 314 | 315 | ``` 316 | cd PiClock 317 | cd Clock 318 | cp ApiKeys-example.py ApiKeys.py 319 | nano ApiKeys.py 320 | ``` 321 | Put your api keys in the file as indicated 322 | ``` 323 | #change this to your API keys 324 | # DarkSky API key 325 | dsapi = 'YOUR DARKSKY API KEY' 326 | # Map API keys -- only needs 1 of the following 327 | # Google Maps API key (if usemapbox is not set in Config) 328 | googleapi = 'YOUR GOOGLE MAPS API KEY' 329 | # Mapbox API key (access_token) [if usemapbox is set in Config] 330 | mbapi = 'YOUR MAPBOX ACCESS TOKEN' 331 | ``` 332 | 333 | ### Configure your PiClock 334 | here's were you tell PiClock where your weather should come from, and the 335 | radar map centers and markers. 336 | 337 | ``` 338 | cd PiClock 339 | cd Clock 340 | cp Config-Example.py Config.py 341 | nano Config.py 342 | ``` 343 | 344 | This file is a python script, subject to python rules and syntax. 345 | The configuration is a set of variables, objects and arrays, 346 | set up in python syntax. The positioning of the {} and () and ',' 347 | are not arbitrary. If you're not familiar with python, use extra 348 | care not to disturb the format while changing the data. 349 | 350 | The first thing is to change the primary_coordinates to yours. That is really 351 | all that is manditory. Further customization of the radar maps can be done in 352 | the Radar section. There you can customize where your radar images are centered 353 | and where the markers appear on those images. Markers are those little red 354 | location pointers. Radar1 and 2 show on the first page, and 3 and 4 show on the 355 | second page of the display (here's a post of about that: 356 | https://www.facebook.com/permalink.php?story_fbid=1371576642857593&id=946361588712436&substory_index=0 ) 357 | 358 | The second thing to change is your NOAA weather radio stream url. You can 359 | find it here: http://noaaweatherradio.org/ They don't put the .mp3 urls 360 | where they are easily accessable, so you need to use your browser to "View Page Source" 361 | in order to find the proper .mp3 url. 362 | 363 | At this point, I'd not recommend many other changes until you have tested 364 | and gotten it running. 365 | 366 | ### Run it! 367 | You'll need to be on the desktop, in a terminal program. 368 | 369 | ``` 370 | cd PiClock 371 | sh startup.sh -n -s 372 | ``` 373 | Your screen should be covered by the PiClock YAY! 374 | 375 | There will be some output on the terminal screen as startup.sh executes. 376 | If everything works, it can be ignored. If for some reason the clock 377 | doesn't work, or maps are missing, etc the output may give a reason 378 | or reasons, which usually reference something to do with the config 379 | file (Config.py) 380 | 381 | ### Logs 382 | The -s option causes no log files to be created, but 383 | instead logs to your terminal screen. If -s is omitted, logs are 384 | created in PiClock/Clock as PyQtPiClock.[1-7].log, which can also help 385 | you find issues. -s is normally omitted when started from the desktop icon 386 | or from crontab. Logs are then created for debugging auto starts. 387 | 388 | ### First Use 389 | 390 | * The space bar or right or left arrows will change the page. 391 | * F2 will start and stop the NOAA weather radio stream 392 | * F4 will close the clock 393 | 394 | If you're using the temperature feature AND you have multiple temperature sensors, 395 | you'll see the clock display: 000000283872:74.6 00000023489:65.4 or something similar. 396 | Note the numbers exactly. Use F4 to stop the clock, 397 | then.. 398 | ``` 399 | nano Temperature/TempNames.py 400 | ``` 401 | Give each number a name, like is shown in the examples in that file 402 | 403 | ### setting the clock to auto start 404 | At this point the clock will only start when you manually start it, as 405 | described in the Run It section. 406 | 407 | Use only one autostart method. 408 | ## Autostart Method 1 409 | (NOT as root) 410 | ``` 411 | cd PiClock 412 | chmod +x PiClock.desktop 413 | ln PiClock.desktop ~/Desktop 414 | mkdir ~/.config/autostart 415 | ln PiClock.desktop ~/.config/autostart 416 | ``` 417 | This puts the a PiClock icon on your desktop. It also runs it when 418 | the desktop starts. 419 | 420 | ## Autostart Method 2 421 | To have it auto start on boot we need to do one more thing, edit the 422 | crontab file as follows: (it will automatically start nano) (NOT as root) 423 | ``` 424 | crontab -e 425 | ``` 426 | and add the following line: 427 | ``` 428 | @reboot sh /home/pi/PiClock/startup.sh 429 | ``` 430 | save the file 431 | and reboot to test 432 | ``` 433 | sudo reboot 434 | ``` 435 | 436 | ## Some notes about startup.sh 437 | startup.sh has a few options: 438 | * -n or --no-delay Don't delay on starting the clock right away (default is 45 seconds delay) 439 | * -d X or --delay X Delay X seconds before starting the clock 440 | * -m X or --message-delay X Delay X seconds while displaying a message on the desktop 441 | 442 | Startup also looks at the various optional PiClock items (Buttons, Temperature, NeoPixel, etc) 443 | and only starts those things that are configured to run. It also checks if they are already 444 | running, and refrains from starting them again if they are. 445 | 446 | ### Switching skins at certain times of the day 447 | This is optional, but if its just too bright at night, a switcher script will kill and restart 448 | PyQtPiClock with an alternate config. 449 | 450 | First you need to set up an alternate config. Config.py is the normal name, so perhaps Config-Night.py 451 | might be appropriate. For a dimmer display use Config-Example-Bedside.py as a guide. 452 | 453 | First we must make switcher.sh executable (git removes the x flags) 454 | ``` 455 | cd PiClock 456 | chmod +x switcher.sh 457 | ``` 458 | Now we'll tell our friend cron to run the switcher script (switcher.sh) on day/night cycles. 459 | Run the cron editor: (should *not* be roor) 460 | ``` 461 | crontab -e 462 | ``` 463 | Add lines similar to this: 464 | ``` 465 | 0 8 * * * sh /home/pi/PiClock/switcher.sh Config 466 | 0 21 * * * sh /home/pi/PiClock/switcher.sh Config-Night 467 | ``` 468 | The 8 there means 8am, to switch to the normal config, and the 21 means switch to Config-Night at 9pm. 469 | More info on crontab can be found here: https://en.wikipedia.org/wiki/Cron 470 | 471 | ### Setting the Pi to auto reboot every day 472 | This is optional but some may want their PiClock to reboot every day. I do this with mine, 473 | but it is probably not needed. 474 | ``` 475 | sudo crontab -e 476 | ``` 477 | add the following line 478 | ``` 479 | 22 3 * * * /sbin/reboot 480 | ``` 481 | save the file 482 | 483 | This sets the reboot to occur at 3:22am every day. Adjust as needed. 484 | 485 | ### Updating to newer/updated versions 486 | Since we pulled the software from github originally, it can be updated 487 | using git and github. 488 | ``` 489 | cd PiClock 490 | git pull 491 | python update.py 492 | ``` 493 | This will automatically update any part(s) of the software that has changed. 494 | The update.py program will then convert any config files as needed. 495 | 496 | You'll want to reboot after the update. 497 | 498 | Note: If you get errors because you've made changes to the base code you might need 499 | ``` 500 | git diff 501 | ``` 502 | To see your changes, so you can back them up 503 | 504 | Then this will update to the current version 505 | ``` 506 | git reset --hard 507 | ``` 508 | (This won't bother your Config.py nor ApiKeys.py because they are not tracked in git. 509 | 510 | Also, if you're using gpio-keys, you may need to remake it: 511 | ``` 512 | cd PiClock/Button 513 | rm gpio-keys 514 | make gpio-keys 515 | ``` 516 | 517 | ### Updating on very old Raspbian versions 518 | If your log shows error messages regarding dateutil or tzlocal you'll need 519 | to install them using pip. Since these are very old versions you'll need to 520 | download them. 521 | 522 | These steps worked on my old Raspbian GNU/Linux 7 (wheezy), which I installed in 523 | 2015. 524 | 525 | ``` 526 | sudo su - # becoming root 527 | wget https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl 528 | wget https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl 529 | wget https://files.pythonhosted.org/packages/61/28/1d3920e4d1d50b19bc5d24398a7cd85cc7b9a75a490570d5a30c57622d34/pytz-2018.9-py2.py3-none-any.whl 530 | wget https://files.pythonhosted.org/packages/cb/89/e3687d3ed99bc882793f82634e9824e62499fdfdc4b1ae39e211c5b05017/tzlocal-1.5.1.tar.gz 531 | wget https://files.pythonhosted.org/packages/53/97/7cc5be0d41443ba5d6b700e749f43716ff87a7ce2dbd87e92fe97e04c369/python-metar-1.4.0.tar.gz 532 | 533 | pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org six-1.16.0-py2.py3-none-any.whl 534 | pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org python_dateutil-2.8.2-py2.py3-none-any.whl 535 | pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org pytz-2018.9-py2.py3-none-any.whl 536 | pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org tzlocal-1.5.1.tar.gz 537 | pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org python-metar-1.4.0.tar.gz 538 | 539 | ``` 540 | 541 | -------------------------------------------------------------------------------- /Documentation/NeoPixel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/NeoPixel.jpg -------------------------------------------------------------------------------- /Documentation/Overview.md: -------------------------------------------------------------------------------- 1 | # Overview of the PiClock 2 | 3 | ## Introduction 4 | 5 | The PiClock is a clock (duh), weather forcast, and radar map display 6 | based on the Raspberry Pi and a display monitor. The display monitor is 7 | assumed to be an HDMI monitor, but it will probably (possibly) work with 8 | the composite output as well, but this is not a design goal. The main 9 | program (Clock/PyQtPiClock.py) will also run on Windows, Mac, and Linux, 10 | as long as python 2.7+ and PyQt4 is installed. 11 | 12 | ~~The Weather data comes from DarkSky using their API ( http://darksky.net/dev/ ). 13 | The maps are from Mapbox ( https://mapbox.com/ ) Google Maps API. 14 | **You must get API Keys from DarkSky and Mapbox or Google in order to make 15 | this work.** It is free for low usage such as this application.~~ 16 | 17 | The Weather data comes from OpenWeatherMap or Tomorrow.io using their API. 18 | The maps are from Mapbox ( https://mapbox.com/ ) or Google Maps API. 19 | **You must get API Keys from OpenWeatherMap or Tomorrow.io and Mapbox 20 | or Google in order to makethis work.** It is free for low usage such 21 | as this application. 22 | 23 | 24 | The PiClock can be customized with several supported additional things: 25 | * RGB LED strips (NeoPixel) to create an ambilight effect 26 | * gpio buttons for changing the view 27 | * IR Remote Control for changing the view 28 | * Streaming the NOAA weather radio stream for your area 29 | 30 | The power usage I've measured is about 35watts with a 19" HDMI Monitor, 27 LEDs and the Pi. 31 | The LEDs contributed 3 or so watts, and I think the Pi is about 2-3 Watts normally. 32 | 33 | This is the basic PiClock, with some options added. 34 | ![PiClock Picture](https://raw.githubusercontent.com/n0bel/PiClock/master/Pictures/20150307_222711.jpg) 35 | 36 | I chose to remove the plastic frame from my monitor and mount the Pi directly 37 | on it, as well as tap power from the display's power supply. 38 | ![PiClock Pi Mounting](https://raw.githubusercontent.com/n0bel/PiClock/master/Pictures/20141222_220127.jpg) 39 | 40 | I've made it work on multiple platforms and form factors. 41 | ![PiClock Pi Mounting](https://raw.githubusercontent.com/n0bel/PiClock/master/Pictures/20150404_165441_Fotor_Collage.jpg) 42 | 43 | And I've made some for friends and family with different customizations. 44 | ![PiClock Pi Mounting](https://raw.githubusercontent.com/n0bel/PiClock/master/Pictures/20150326_225305_Fotor_Collage.jpg) 45 | 46 | 47 | ## List of materials 48 | 49 | So what do you need to build a PiClock? 50 | 51 | * A Raspberry Pi (revision 2) Model B, or B+ or Pi 2 Model B 52 | * A Display Monitor & Cable 53 | * Power Supply (or if you're ambitious tap your display power supply, 54 | you'll probably need a switching down regulator to 5v) Remember 55 | the Pi likes something that can source up to 2A. 56 | * A USB Keyboard and Mouse for setup (if you want something small 57 | and semi-permanent, I've had good luck with this: 58 | https://www.google.com/search?q=iPazzPort+2.4G+Mini+Wireless+Keyboard 59 | I like the one with the mousepad on the side) 60 | * USB Wifi or Internet Connection 61 | 62 | Optional things 63 | 64 | * One or more DS18B20s for showing the inside temperature ( https://www.google.com/#q=ds18b20 ) 65 | * A string of WS2818 based RGB LEDs for the AmbiLight effect. At 40ma per LED, and 30 or so 66 | LEDs you're quickly up to needing an extra 1.2A from the power supply. Size it appropriately. 67 | One option is https://learn.adafruit.com/adafruit-neopixel-uberguide/overview) 68 | * A TSOP4838 IR Receiver to flip the page display of the PiClock (https://www.google.com/search?q=tsop4838) 69 | * An IR Remote control ( I use this little guy: https://www.google.com/search?q=Mini+Universal+Infrared+IR+TV+Set+Remote+Control+Keychain ) 70 | * Button or buttons connected to some GPIO pins (and a ground pin) for flipping pages like the IR remote 71 | 72 | ## What else? 73 | 74 | The Hardware guide ( https://github.com/n0bel/PiClock/blob/master/Documentation/Hardware.md ) 75 | gives more details about how to wire/connect the various extras. 76 | 77 | The Install guide ( https://github.com/n0bel/PiClock/blob/master/Documentation/Install.md ) 78 | steps through all the things that you need to do to a stock Raspbian image to make the PiClock work. 79 | 80 | ## Not a Pi Person? 81 | 82 | If you want to use the PiClock on your desktop (not your Pi), I've created instructinos for that 83 | https://github.com/n0bel/PiClock/blob/master/Documentation/Install-Clock-Only.md 84 | 85 | 86 | ## History 87 | 88 | It all started one Satuday afternoon when I was feeling bored. My super duper radio 89 | controlled clock ( you know those AccuRite clocks) was WRONG!. Apparently the 90 | daylight savings time adjustment was coded to the pre-2007 dates. I was going 91 | to go get something new.. when I spotted an unused monitor in the corner of my 92 | livingroom... My eyes flicked back and forth between it and the wall. I had 93 | recently been playing with a Raspberry Pi Model B, and of course the idea was born. 94 | 95 | The initial clock was built as a static web page hosted in the Pi itself and run from 96 | the Midori browser in kiosk mode. Javascript and Ajax methods were used to pull 97 | the forecast from some free weather site (don't remember) and the local NWS radar 98 | image. The Pi ran at about 60% cpu, having to move the second hand once per second 99 | while re-rendering the other hands and clock face layers. 100 | 101 | After well over a year, and some minor changes, I decided to give it a facelift, 102 | change the weather to Weather Underground and the background maps to Google Maps. 103 | Well the Midori browser really had a tough time keeping up with all that going on. 104 | You could see it skipping past seconds two at a time. And the animated radar 105 | GIFs would stall more often than not. Yes I tried Ephemeral and it was worse! 106 | 107 | I decided to rewrite the whole thing in Python. Why? I decided I needed to learn 108 | Python in more than a passing way. For some (unfathomable reason to me) Python is 109 | the language of choice for Pi's. It took a while to settle on a GUI framework. 110 | The primary issue on most of the GUIs was lack of image transparency support. 111 | Qt4 and its Python wrapper PyQt4 is what I finally chose. 112 | 113 | The details of this evolution are on my blog http://n0bel.net/v1/index.php/projects/raspberry-pi-clock 114 | as well as newer postings and updates. Some of my friends have been treated (subjected) 115 | to more timely updates via my public facebook page https://www.facebook.com/pages/Kevin-N0BEL/946361588712436 116 | 117 | And of course I tweet https://twitter.com/KevinN0BEL, Pin https://www.pinterest.com/kevinuhir/, 118 | Instagram https://instagram.com/kevin_n0bel/, and hack https://hackaday.io/n0bel 119 | -------------------------------------------------------------------------------- /Documentation/ds18b20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/ds18b20.jpg -------------------------------------------------------------------------------- /Documentation/gpiobuttons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/gpiobuttons.jpg -------------------------------------------------------------------------------- /Documentation/tsop4838.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Documentation/tsop4838.jpg -------------------------------------------------------------------------------- /IR/IRCodes.pl: -------------------------------------------------------------------------------- 1 | open(C,"/etc/lirc/lircd.conf"); 2 | 3 | while() 4 | { 5 | if (m/(KEY_[A-Z0-9]+)\s+([0-9a-fx]+)/i) 6 | { 7 | $k{$2} = $1; 8 | } 9 | } 10 | close C; 11 | foreach (sort keys %k) 12 | { 13 | print $_." ".$k{$_}."\n"; 14 | } 15 | open(X,"mode2 -d /dev/lirc0|"); 16 | $ps = 0; 17 | $pp = 0; 18 | $bc = 0; 19 | while() 20 | { 21 | #print; 22 | chop; 23 | ($c, $t) = split; 24 | if ($c eq 'pulse') 25 | { 26 | if ($t > 8000) { $b = 0; $bc = 0; $ps = 0; $pp = 0; $lp = $t; next; } 27 | if ($t > 400 && $t < 700) { $pp = 1; } 28 | } 29 | if ($c eq 'space') 30 | { 31 | if ($t > 10000) 32 | { 33 | printf("*** %016x %016x %d %d\n",$b,$b^0x00ff00ff,$lp, $ls); 34 | $s = sprintf("0x%016x",$b); 35 | if (defined($k{$s})) 36 | { 37 | print "********* $k{$s}\n"; 38 | } 39 | } 40 | if ($t > 4000) { $b = 0; $bc = 0; $ps = 0; $pp = 0; $ls = $t; next; } 41 | if ($t > 400 && $t < 700) { $ps = 1; } 42 | if ($t > 1400 && $t < 1800) { $ps = 2; } 43 | } 44 | if ($ps > 0 && $pp > 0) 45 | { 46 | $bc++; 47 | if ($pp == 1 && $ps == 2) 48 | { 49 | $b = $b << 1; 50 | $b = $b | 1; 51 | #print "*1* $bc\n"; 52 | } 53 | if ($pp == 1 && $ps == 1) 54 | { 55 | $b = $b << 1; 56 | #print "*0* $bc\n"; 57 | } 58 | $ps = 0; 59 | $pp = 0; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /IR/lircd.conf: -------------------------------------------------------------------------------- 1 | begin remote 2 | 3 | name KeyFobRemote 4 | bits 32 5 | flags SPACE_ENC 6 | eps 20 7 | aeps 200 8 | 9 | header 8800 4400 10 | one 550 1650 11 | zero 550 550 12 | ptrail 550 13 | repeat 8800 2200 14 | gap 38500 15 | toggle_bit 0 16 | 17 | frequency 38000 18 | 19 | begin codes 20 | KEY_F1 0x0000000008f7e817 21 | KEY_DOWN 0x0000000008f718e7 22 | KEY_UP 0x0000000008f79867 23 | KEY_RIGHT 0x0000000008f748b7 24 | KEY_LEFT 0x0000000008f7a857 25 | KEY_F2 0x0000000008f7d02f 26 | KEY_F3 0x0000000008f7906f 27 | end codes 28 | 29 | end remote 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Kevin Uhlir 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Leds/NeoAmbi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Must be run under sudo 3 | # Requires: sudo pip install rpi_ws281x 4 | 5 | import _rpi_ws281x as ws 6 | from time import sleep, time 7 | from math import modf 8 | import colorsys 9 | 10 | # LED configuration. 11 | LED_COUNT = 27 # How many LEDs to light. 12 | 13 | # 0..2 14 | LED_CHANNEL = 0 15 | 16 | # Frequency of the LED signal. Should be 800khz or 400khz 17 | LED_FREQ_HZ = 800000 18 | 19 | 20 | # DMA channel to use, can be 0-14. 21 | LED_DMA_NUM = 5 22 | 23 | # GPIO connected to the LED signal line. Must support PWM 24 | LED_GPIO = 18 25 | 26 | # Set to 0 for darkest and 255 for brightest 27 | LED_BRIGHTNESS = 255 28 | 29 | # Set to 1 to invert the LED signal, good if using NPN 30 | # transistor as a 3.3V->5V level converter. Keep at 0 31 | # for a normal/non-inverted signal. 32 | LED_INVERT = 0 33 | 34 | 35 | # from RGB in float 0..1.0 to NeoPixel Color 0..255 36 | def toNeoPixelColor(r, g, b): 37 | if r > 1: 38 | r = 1 39 | if g > 1: 40 | g = 1 41 | if b > 1: 42 | b = 1 43 | if r < 0: 44 | r = 0 45 | if g < 0: 46 | g = 0 47 | if b < 0: 48 | b = 0 49 | c = ((int(r * 255) & 0xff) << 16 | 50 | (int(g * 255) & 0xff) << 8 | (int(b * 255) & 0xff)) 51 | return(c) 52 | 53 | 54 | leds = ws.new_ws2811_t() 55 | 56 | channel = ws.ws2811_channel_get(leds, LED_CHANNEL) 57 | 58 | ws.ws2811_channel_t_count_set(channel, LED_COUNT) 59 | ws.ws2811_channel_t_gpionum_set(channel, LED_GPIO) 60 | ws.ws2811_channel_t_invert_set(channel, LED_INVERT) 61 | ws.ws2811_channel_t_brightness_set(channel, LED_BRIGHTNESS) 62 | 63 | ws.ws2811_t_freq_set(leds, LED_FREQ_HZ) 64 | ws.ws2811_t_dmanum_set(leds, LED_DMA_NUM) 65 | 66 | resp = ws.ws2811_init(leds) 67 | if resp != 0: 68 | raise RuntimeError('ws2811_init failed with code {0}'.format(resp)) 69 | 70 | try: 71 | offset = 0 72 | while True: 73 | (fractionOfMinute, dummy) = modf(time() / 60.0) 74 | for i in range(LED_COUNT): 75 | p = i / float(LED_COUNT) # 0.0..1.0 by position on string 76 | q = p + fractionOfMinute 77 | while(q > 1): 78 | q = q - 1.0 # normalize for overflow 79 | (r, g, b) = colorsys.hsv_to_rgb(q, 1.0, 1.0) 80 | ws.ws2811_led_set(channel, i, toNeoPixelColor(r, g, b)) 81 | 82 | resp = ws.ws2811_render(leds) 83 | if resp != 0: 84 | raise RuntimeError('ws2811_render failed with code {0}'. 85 | format(resp)) 86 | 87 | sleep(0.2) 88 | 89 | finally: 90 | for i in range(LED_COUNT): 91 | ws.ws2811_led_set(channel, i, 0) 92 | resp = ws.ws2811_render(leds) 93 | if resp != 0: 94 | raise RuntimeError('ws2811_render failed with code {0}'.format(resp)) 95 | ws.ws2811_fini(leds) 96 | ws.delete_ws2811_t(leds) 97 | -------------------------------------------------------------------------------- /PiClock.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Type=Application 4 | Name=PiClock 5 | Comment= 6 | Exec=/bin/sh -c "/bin/sh ~/PiClock/startup.sh -m 15" 7 | StartupNotify=false 8 | Terminal=false 9 | Hidden=false 10 | -------------------------------------------------------------------------------- /Pictures/20141222_220127.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/20141222_220127.jpg -------------------------------------------------------------------------------- /Pictures/20141227_174953.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/20141227_174953.jpg -------------------------------------------------------------------------------- /Pictures/2015-05-10_17-01-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/2015-05-10_17-01-52.png -------------------------------------------------------------------------------- /Pictures/2015-05-16_17-36-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/2015-05-16_17-36-06.png -------------------------------------------------------------------------------- /Pictures/20150307_222711.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/20150307_222711.jpg -------------------------------------------------------------------------------- /Pictures/20150326_225245.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/20150326_225245.jpg -------------------------------------------------------------------------------- /Pictures/20150326_225305_Fotor_Collage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/20150326_225305_Fotor_Collage.jpg -------------------------------------------------------------------------------- /Pictures/20150404_165441_Fotor_Collage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/20150404_165441_Fotor_Collage.jpg -------------------------------------------------------------------------------- /Pictures/20150412_182821a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/Pictures/20150412_182821a.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PiClock 2 | A Fancy Clock built around a monitor and a Raspberry Pi 3 | 4 | ![PiClock Picture](https://raw.githubusercontent.com/n0bel/PiClock/master/Pictures/20150307_222711.jpg) 5 | 6 | This project started out as a way to waste a Saturday afternoon. 7 | I had a Raspberry Pi and an extra monitor and had just taken down an analog clock from my livingroom wall. 8 | I was contemplating getting a radio sync'ed analog clock to replace it, so I didn't have to worry about 9 | it being accurate. 10 | 11 | But instead the PiClock was born. 12 | 13 | The early days and evolution of it are chronicled on my blog http://n0bel.net/v1/index.php/projects/raspberry-pi-clock 14 | 15 | If you want to build your own, I'd suggest starting with the overview 16 | https://github.com/n0bel/PiClock/blob/master/Documentation/Overview.md 17 | 18 | If you want to use the PiClock on your desktop (not your Pi), I'd suggest using these instructions. 19 | https://github.com/n0bel/PiClock/blob/master/Documentation/Install-Clock-Only.md 20 | 21 | All of the extra hardware (IR Remote, GPIO buttons, Temperature, LEDs) are optional, so you can then jump to the install guide 22 | https://github.com/n0bel/PiClock/blob/master/Documentation/Install.md 23 | 24 | Of course you can jump to the hardware guide anytime https://github.com/n0bel/PiClock/blob/master/Documentation/Hardware.md 25 | -------------------------------------------------------------------------------- /Temperature/TempNames.py: -------------------------------------------------------------------------------- 1 | # these are the IDs of the DS18B20's 2 | # and their corresponding names displayed on the clock 3 | sensornames = { 4 | '0000058e0f0c': 'Inside', 5 | '0000031b462b': 'Closer', 6 | '0000031b3dae': 'Farther', 7 | '0000031b54e7': 'Outside', 8 | '0000031b4f09': 'Inside2' 9 | } 10 | -------------------------------------------------------------------------------- /Temperature/TempServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # small web server that polls 18B20's that it finds 3 | # and makes them available as a json response 4 | # see TempNames.py for sensor id to name mapping 5 | # 6 | from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 7 | from w1thermsensor import W1ThermSensor 8 | import json 9 | import time 10 | import socket 11 | from threading import Thread, Lock 12 | from TempNames import sensornames 13 | 14 | temps = {} 15 | temptimes = {} 16 | lock = Lock() 17 | 18 | PORT_NUMBER = 48213 19 | 20 | # This class will handles any incoming request from 21 | # the browser 22 | 23 | 24 | class myHandler(BaseHTTPRequestHandler): 25 | 26 | def do_OPTIONS(self): 27 | self.send_response(200, "ok") 28 | self.send_header('Access-Control-Allow-Origin', '*') 29 | self.send_header('Access-Control-Allow-Methods', '*') 30 | self.send_header('Access-Control-Allow-Headers', 31 | "x-requested-with, origin, x-csrftoken," + 32 | " content-type, accept" 33 | ) 34 | self.end_headers() 35 | 36 | def do_GET(self): 37 | global temps, lock 38 | self.send_response(200) 39 | self.send_header('Content-type', 'text/json') 40 | self.send_header('Access-Control-Allow-Origin', '*') 41 | self.end_headers() 42 | s = {'temp': '', 'temps': {}} 43 | lock.acquire() 44 | for k in temps: 45 | if s['temp'] == '': 46 | s['temp'] = "%.1f" % temps[k] 47 | s['temps'][sensorname(k)] = "%.1f" % temps[k] 48 | lock.release() 49 | self.wfile.write(json.dumps(s)) 50 | 51 | 52 | def sensorname(str): 53 | try: 54 | return sensornames[str] 55 | except KeyError: 56 | return 'temp-' + str 57 | 58 | 59 | def t_http(): 60 | try: 61 | server = HTTPServer(('0.0.0.0', PORT_NUMBER), myHandler) 62 | print 'Started httpserver on port ', PORT_NUMBER 63 | server.serve_forever() 64 | except: 65 | server.close() 66 | 67 | 68 | def t_udp(): 69 | global temps, lock 70 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 71 | server_address = ('', 53535) 72 | sock.bind(server_address) 73 | while True: 74 | data, address = sock.recvfrom(4096) 75 | (addr, temp) = data.split(':') 76 | saddr = [addr[i:i + 2] for i in range(0, len(addr), 2)] 77 | saddr.reverse() 78 | saddr = saddr[1:7] 79 | addr = ''.join(saddr) 80 | tempf = float(temp) * 9.0 / 5.0 + 32.0 81 | lock.acquire() 82 | temps[addr] = tempf 83 | temptimes[addr] = time.time() 84 | lock.release() 85 | print 'udp>' + addr + ':' + str(tempf) 86 | 87 | 88 | def t_temp(): 89 | while True: 90 | for sensor in W1ThermSensor.get_available_sensors(): 91 | lock.acquire() 92 | temps[sensor.id] = sensor.get_temperature(W1ThermSensor.DEGREES_F) 93 | temptimes[sensor.id] = time.time() 94 | print 'hwr>' + sensor.id + ':' + str(temps[sensor.id]) 95 | lock.release() 96 | 97 | lock.acquire() 98 | todelete = [] 99 | expire = time.time() - 60 * 10 100 | for t in temptimes: 101 | if temptimes[t] < expire: 102 | todelete.append(t) 103 | for t in todelete: 104 | temptimes.pop(t, None) 105 | temps.pop(t, None) 106 | print "del>" + t 107 | lock.release() 108 | 109 | time.sleep(120) 110 | 111 | t_httpt = Thread(target=t_http) 112 | t_httpt.daemon = True 113 | t_httpt.start() 114 | 115 | t_udpt = Thread(target=t_udp) 116 | t_udpt.daemon = True 117 | t_udpt.start() 118 | 119 | t_tempt = Thread(target=t_temp) 120 | t_tempt.daemon = True 121 | t_tempt.start() 122 | 123 | try: 124 | while True: 125 | time.sleep(.1) 126 | except KeyboardInterrupt: 127 | exit() 128 | -------------------------------------------------------------------------------- /gimp/Readme.md: -------------------------------------------------------------------------------- 1 | # Clock face and background source files 2 | 3 | These are GIMP files which are the source files for the images I've created for the PiClock. -------------------------------------------------------------------------------- /gimp/clockbackground.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/clockbackground.xcf -------------------------------------------------------------------------------- /gimp/clockbackground5.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/clockbackground5.xcf -------------------------------------------------------------------------------- /gimp/clockface3.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/clockface3.xcf -------------------------------------------------------------------------------- /gimp/hourhand.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/hourhand.xcf -------------------------------------------------------------------------------- /gimp/jeansxcf.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/jeansxcf.xcf -------------------------------------------------------------------------------- /gimp/minhand.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/minhand.xcf -------------------------------------------------------------------------------- /gimp/sechand.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/sechand.xcf -------------------------------------------------------------------------------- /gimp/squares2.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/squares2.xcf -------------------------------------------------------------------------------- /gimp/squres1.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n0bel/PiClock/e18e5b1a9241035d905f143a6026a33bc21e362e/gimp/squres1.xcf -------------------------------------------------------------------------------- /startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Startup script for the PiClock 3 | # 4 | # Designed to be started from PiClock.desktop (autostart) 5 | # 6 | # or alternatively from crontab as follows 7 | #@reboot sh /home/pi/PiClock/startup.sh 8 | 9 | # 10 | cd $HOME/PiClock 11 | 12 | # 13 | if [ "$DISPLAY" = "" ] 14 | then 15 | export DISPLAY=:0 16 | fi 17 | 18 | # wait for Xwindows and the desktop to start up 19 | MSG="echo Waiting 45 seconds before starting" 20 | DELAY="sleep 45" 21 | if [ "$1" = "-n" -o "$1" = "--no-sleep" -o "$1" = "--no-delay" ] 22 | then 23 | MSG="" 24 | DELAY="" 25 | shift 26 | fi 27 | if [ "$1" = "-d" -o "$1" = "--delay" ] 28 | then 29 | MSG="echo Waiting $2 seconds before starting" 30 | DELAY="sleep $2" 31 | shift 32 | shift 33 | fi 34 | if [ "$1" = "-m" -o "$1" = "--message-delay" ] 35 | then 36 | MSG="echo Waiting $2 seconds for response before starting" 37 | #DELAY="xmessage -buttons Now:0,Cancel:1 -default Now -timeout $2 Starting PiClock in $2 seconds" 38 | DELAY='zenity --question --title PiClock --ok-label=Now --cancel-label=Cancel --timeout '$2' --text "Starting PiClock in '$2' seconds" >/dev/null 2>&1' 39 | shift 40 | shift 41 | fi 42 | 43 | $MSG 44 | eval $DELAY 45 | if [ $? -eq 1 ] 46 | then 47 | 48 | echo "PiClock Cancelled" 49 | exit 0 50 | fi 51 | 52 | #xmessage -timeout 5 Starting PiClock....... & 53 | zenity --info --timeout 3 --text "Starting PiClock......." >/dev/null 2>&1 & 54 | 55 | # stop screen blanking 56 | echo "Disabling screen blanking...." 57 | xset s off 58 | xset -dpms 59 | xset s noblank 60 | 61 | # get rid of mouse cursor 62 | pgrep unclutter >/dev/null 2>&1 63 | if [ $? -eq 1 ] 64 | then 65 | unclutter >/dev/null 2>&1 & 66 | fi 67 | 68 | echo "Setting sound to max (assuming Monitor Tv controls volume)...." 69 | # push sound level to maximum 70 | amixer cset numid=1 -- 400 >/dev/null 2>&1 71 | 72 | # NeoPixel AmbiLights 73 | echo "Checking for NeoPixels Ambilight..." 74 | cd Leds 75 | python -c "import rpi_ws281x" >/dev/null 2>&1 76 | if [ $? -eq 0 ] 77 | then 78 | pgrep -f NeoAmbi.py 79 | if [ $? -eq 1 ] 80 | then 81 | echo "Starting NeoPixel Ambilight Service..." 82 | sudo python NeoAmbi.py & 83 | fi 84 | fi 85 | cd .. 86 | 87 | echo "Checking for GPIO Buttons..." 88 | # gpio button to keyboard input 89 | if [ -x Button/gpio-keys ] 90 | then 91 | pgrep -f gpio-keys 92 | if [ $? -eq 1 ] 93 | then 94 | echo "Starting gpio-keys Service..." 95 | sudo Button/gpio-keys 23:KEY_SPACE 24:KEY_F2 25:KEY_UP & 96 | fi 97 | fi 98 | 99 | echo "Checking for Temperature Sensors..." 100 | # for temperature sensor(s) on One Wire bus 101 | python -c "import w1thermsensor" >/dev/null 2>&1 102 | if [ $? -eq 0 ] 103 | then 104 | pgrep -f TempServer.py 105 | if [ $? -eq 1 ] 106 | then 107 | echo "Starting Temperature Service..." 108 | cd Temperature 109 | python TempServer.py & 110 | cd .. 111 | fi 112 | fi 113 | 114 | # the main app 115 | cd Clock 116 | if [ "$1" = "-s" -o "$1" = "--screen-log" ] 117 | then 118 | echo "Starting PiClock.... logging to screen." 119 | python -u PyQtPiClock.py 120 | else 121 | # create a new log file name, max of 7 log files 122 | echo "Rotating log files...." 123 | rm PyQtPiClock.7.log >/dev/null 2>&1 124 | mv PyQtPiClock.6.log PyQtPiClock.7.log >/dev/null 2>&1 125 | mv PyQtPiClock.5.log PyQtPiClock.6.log >/dev/null 2>&1 126 | mv PyQtPiClock.4.log PyQtPiClock.5.log >/dev/null 2>&1 127 | mv PyQtPiClock.3.log PyQtPiClock.4.log >/dev/null 2>&1 128 | mv PyQtPiClock.2.log PyQtPiClock.3.log >/dev/null 2>&1 129 | mv PyQtPiClock.1.log PyQtPiClock.2.log >/dev/null 2>&1 130 | echo "Starting PiClock.... logging to Clock/PyQtPiClock.1.log " 131 | python -u PyQtPiClock.py >PyQtPiClock.1.log 2>&1 132 | fi 133 | -------------------------------------------------------------------------------- /switcher.sh: -------------------------------------------------------------------------------- 1 | cd $HOME/PiClock 2 | pkill -INT -f PyQtPiClock.py 3 | cd Clock 4 | if [ "$DISPLAY" = "" ] 5 | then 6 | export DISPLAY=:0 7 | fi 8 | # the main app 9 | # create a new log file name, max of 7 log files 10 | echo "Rotating log files...." 11 | rm PyQtPiClock.7.log >/dev/null 2>&1 12 | mv PyQtPiClock.6.log PyQtPiClock.7.log >/dev/null 2>&1 13 | mv PyQtPiClock.5.log PyQtPiClock.6.log >/dev/null 2>&1 14 | mv PyQtPiClock.4.log PyQtPiClock.5.log >/dev/null 2>&1 15 | mv PyQtPiClock.3.log PyQtPiClock.4.log >/dev/null 2>&1 16 | mv PyQtPiClock.2.log PyQtPiClock.3.log >/dev/null 2>&1 17 | mv PyQtPiClock.1.log PyQtPiClock.2.log >/dev/null 2>&1 18 | # start the clock 19 | echo "Starting PiClock...." 20 | python -u PyQtPiClock.py $1 >PyQtPiClock.1.log 2>&1 & 21 | -------------------------------------------------------------------------------- /update.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os.path 3 | import os 4 | import re 5 | 6 | print "Updating Python Modules" 7 | print "Updating python-dateutil" 8 | os.system("sudo pip install python-dateutil --upgrade") 9 | print "Updating tzlocal" 10 | os.system("sudo pip install tzlocal --upgrade") 11 | print "Updating python-metar" 12 | os.system("sudo pip install python-metar --upgrade") 13 | 14 | buttonFileName = 'Button/gpio-keys' 15 | print "Checking " + buttonFileName 16 | if os.path.isfile(buttonFileName): 17 | try: 18 | print "Setting proper permissions on " + buttonFileName 19 | os.chmod(buttonFileName, 0744) 20 | except: 21 | pass 22 | 23 | apikeysFileName = 'Clock/ApiKeys.py' 24 | wuapi_re = re.compile('\\s*wuapi\\s*=') 25 | dsapi_re = re.compile('\\s*dsapi\\s*=') 26 | ccapi_re = re.compile('\\s*ccapi\\s*=') 27 | owmapi_re = re.compile('\\s*owmapi\\s*=') 28 | 29 | print "Checking " + apikeysFileName 30 | if (os.path.isfile(apikeysFileName)): 31 | altered = False 32 | foundcc = False 33 | foundowm = False 34 | newfile = '' 35 | apikeys = open(apikeysFileName, "r") 36 | for aline in apikeys: 37 | if ccapi_re.match(aline): 38 | foundcc = True 39 | if owmapi_re.match(aline): 40 | foundwom = True 41 | if wuapi_re.match(aline): 42 | print "Removing wuapi key from " + apikeysFileName 43 | altered = True 44 | if dsapi_re.match(aline): 45 | print "Removing dsapi key from " + apikeysFileName 46 | altered = True 47 | else: 48 | newfile += aline 49 | apikeys.close() 50 | 51 | if not foundcc and not foundowm: 52 | print "This version of PiClock requires a openweathermap api key." 53 | print "https://openweathermap.org/price use the Free option" 54 | print "Enter your openweathermap api key." 55 | print "key:", 56 | k = sys.stdin.readline() 57 | k = k.strip() 58 | if len(k) > 1: 59 | newfile += "owmapi = '" + k + "'" 60 | altered = True 61 | 62 | if altered: 63 | print "Writing Updated " + apikeysFileName 64 | apikeys = open(apikeysFileName, "w") 65 | apikeys.write(newfile) 66 | apikeys.close() 67 | else: 68 | print "No changes made to " + apikeysFileName 69 | 70 | try: 71 | from rpi_ws281x import * # NOQA 72 | except: 73 | print "NeoAmbi.py now uses rpi-ws281x/rpi-ws281x-python" 74 | print "Please install it as follows:" 75 | print "sudo pip install rpi_ws281x" 76 | --------------------------------------------------------------------------------