Skip to content

Instantly share code, notes, and snippets.

@vladkorotnev
Last active October 9, 2016 17:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vladkorotnev/63a6d27a9a4426aabab7 to your computer and use it in GitHub Desktop.
Save vladkorotnev/63a6d27a9a4426aabab7 to your computer and use it in GitHub Desktop.
radio 1.3 ~~ Internet - FM - Weather - FM Transmitter - Transliteration of track titles - Cool text effects - More to come
from datetime import *
def generateTable(sunriseString='4:38 AM', sunsetString='9:58 PM'):
sunrise = datetime.strptime(sunriseString, '%I:%M %p')
sunset = datetime.strptime(sunsetString, '%I:%M %p')
sunriseIndex = sunrise.hour + (1 if sunrise.minute >= 30 else 0)
sunsetIndex = sunset.hour + (1 if sunset.minute >= 30 else 0)
peakIndex = sunriseIndex + 4
peakEndIndex = sunsetIndex - 4
if sunsetIndex > 23:
sunsetIndex = 23
generatedTable = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
for i in range(0,sunriseIndex-1):
generatedTable[i] = 2
generatedTable[sunriseIndex-1]=3
generatedTable[sunriseIndex] = 4
stepping = 3.0/(peakIndex-sunriseIndex)
prev = 4
for i in range(sunriseIndex+1,peakIndex+1):
prev = prev + stepping
generatedTable[i] = int(prev)
for i in range(peakIndex+1,peakEndIndex+1):
generatedTable[i]=7
prev = 7
stepping = 4.0/(sunsetIndex-peakEndIndex)
for i in range(peakEndIndex+1,sunsetIndex+1):
prev = prev - stepping
generatedTable[i] = int(prev)
for i in range(sunsetIndex+1, len(generatedTable)):
generatedTable[i] = 2
return generatedTable
def printTable(tableToPrint):
for i in reversed(range(0,8)):
lout = str(i)+" "
for j in range(0,len(tableToPrint)):
if tableToPrint[j] == i:
lout = lout + "**"
elif tableToPrint[j] > i:
lout = lout + "||"
elif tableToPrint[j] < i:
lout = lout + " "
print lout
lout = " "
for i in (range(0,len(tableToPrint))):
sis = str(i)
if len(sis) < 2:
sis = sis+" "
lout = lout + sis
print lout
sox -t raw -b 16 -e signed-integer -r$1 -c 2 /tmp/mpd.fifo -t wav - |sudo /pifm/PiFmRds/src/pi_fm_rds -freq $2 -ps "" -rt '' -audio -
#!/bin/bash
/usr/local/bin/rtl_fm -g 34 -f $1 -M fm -s 192000 -r 192000 -F 0 -E deemp - | /usr/bin/aplay -r 192000 -f S16_LE
import wiringpi2 as w
from threading import Thread
import time
ST_BREATHE = 2
ST_BLINK = 1 # Reserved
ST_GENERIC = 0
ST_BLIHOLD = -1 #reserved
PW_PIN = 9
YE_PIN = 10
GR_PIN = 11
class LED:
state = ST_GENERIC
pin = 0
value = 0
breathRate = 5
breathFloor = 50
blinkRate = 1
def __init__(self, pin, initialValue=0):
w.wiringPiSetupGpio()
self.pin = pin
self.value = initialValue
w.pinMode(self.pin, 1)
w.softPwmCreate(self.pin,0,100)
self._setValue(self.value)
def _setValue(self, value):
w.softPwmWrite(self.pin, int(value))
def _brightRange(self, level, src):
return (range(src, level) if src < level else reversed(range(level, src)))
def setValue(self, value, smooth=True, smoothDelay=2):
if self.state != ST_GENERIC:
self.value = value
self.state = ST_GENERIC
return
if smooth:
for i in self._brightRange(value, self.value):
self._setValue(i)
w.delay(smoothDelay)
self._setValue(value)
self.value = value
def _breather(self):
while self.state == ST_BREATHE or self.state == ST_BLIHOLD:
for i in self._brightRange(self.breathFloor, self.value):
if self.state == ST_BREATHE:
self._setValue(i)
w.delay(self.breathRate)
time.sleep(self.breathRate/10)
for i in self._brightRange(self.value, self.breathFloor):
if self.state == ST_BREATHE:
self._setValue(i)
w.delay(self.breathRate)
time.sleep(self.breathRate/10)
self.setValue(self.value, smooth=True)
def startBreathing(self, val=100, floor=15, rate=15):
self.breathRate = rate
self.breathFloor=floor
if self.state == ST_BREATHE:
self.value = val
return
self.setValue(val, True)
self.state = ST_BREATHE
Thread(target=self._breather).start()
def blinkOnce(self):
oldState = self.state
self.state=ST_BLIHOLD
if not self.value == 50:
self._setValue(100-self.value)
w.delay(50)
self._setValue(self.value)
else:
self._setValue(0)
w.delay(50)
self._setValue(50)
self.state = oldState
# Please make this file available to others
# by sending it to <lirc@bartelmus.de>
#
# this config file was automatically generated
# using lirc-0.9.0-pre1(default) on Fri May 30 11:53:01 2014
#
# contributed by
#
# brand: /etc/lirc/lircd.conf
# model no. of remote control:
# devices being controlled by this remote:
#
begin remote
name /etc/lirc/lircd.conf
flags RAW_CODES
eps 30
aeps 100
gap 9105
begin raw_codes
name key_wakeup
9128 4394 647 488 650 466
673 453 683 424 664 470
639 470 634 499 638 470
660 475 679 429 653 485
631 471 631 1638 681 426
681 453 665 443 641 493
635 472 642 498 661 441
680 454 654 454 638 496
634 474 642 1625 684 1562
684 1587 683 1553 696 1571
692 1550 704 1564 703 1538
705
name key_sat
9150 4426 619 487 639 469
827 299 642 474 630 505
625 474 641 519 604 502
608 528 604 496 612 528
606 501 613 1669 596 500
619 522 597 553 565 523
607 1644 597 526 606 503
600 583 556 515 585 539
597 516 591 1678 589 515
592 1682 640 1598 601 1662
604 1646 599 1662 603 1640
599
name key_audio
9141 4391 628 520 610 498
601 748 386 523 583 554
586 499 644 497 596 504
604 530 601 505 603 532
603 521 587 1667 600 505
603 531 605 505 651 1619
600 506 644 1815 413 1641
632 499 600 505 603 532
600 509 600 545 587 1730
644 400 603 506 596 1683
592 1646 594 1681 585 1650
597
name key_mute
9119 4420 623 502 626 481
627 507 628 480 628 505
628 480 618 517 613 495
606 527 611 497 608 526
605 503 605 1663 609 500
608 524 602 507 602 532
600 507 601 534 599 1642
601 1672 596 507 600 534
598 510 600 1668 601 1644
611 1659 596 507 599 534
599 1659 581 1669 603 1639
611
name key_1
9140 4399 609 520 610 500
607 527 604 504 604 529
604 506 631 501 602 556
559 525 604 504 607 526
608 506 603 1704 567 535
571 526 605 504 597 1670
605 1642 604 524 631 483
594 591 545 519 577 562
572 521 641 497 580 520
592 1685 573 1678 572 1681
588 1657 579 1685 596 1650
588
name key_2
9124 4427 611 515 638 478
599 539 601 508 595 537
630 479 591 538 596 507
601 541 593 506 598 537
598 511 599 1843 434 500
586 549 590 516 595 540
589 519 583 1682 588 524
591 602 528 522 579 559
571 531 582 1694 570 1665
583 553 572 1691 552 1695
579 1658 581 1692 575 1664
581
name key_3
9207 4312 611 567 562 489
613 521 651 458 602 547
593 498 607 531 621 485
604 549 749 366 577 535
600 503 605 1693 575 503
608 525 617 494 621 1650
595 513 586 1682 600 507
602 528 601 511 579 552
591 522 574 575 567 1667
577 547 580 1666 576 1687
586 1658 579 1680 597 1649
588
name key_4
9101 4429 609 525 609 497
608 527 603 504 603 531
603 506 601 532 601 508
601 532 632 476 607 527
602 506 599 1669 596 513
597 536 599 511 592 540
588 1661 580 1682 594 513
591 542 584 525 579 560
580 528 574 1702 566 528
577 557 577 1665 580 1690
576 1666 575 1690 581 1663
576
name key_5
9116 4424 608 536 595 498
609 525 607 506 599 532
603 511 698 447 586 503
601 533 601 504 652 482
608 505 607 1660 602 504
607 526 600 510 646 1627
596 1640 612 1660 595 508
601 533 596 515 599 533
602 574 529 540 590 647
455 548 593 1653 585 1776
488 1657 582 1680 603 1646
589
name key_6
9115 4418 645 488 622 487
614 521 606 501 607 527
607 502 608 525 605 503
602 534 604 503 600 534
601 506 601 1667 599 507
601 535 599 508 599 536
603 504 599 536 592 1648
591 545 593 514 596 538
596 512 590 1684 584 1651
597 1673 593 535 563 1713
566 1667 570 1702 562 1677
574
name key_7
9111 4430 608 526 606 502
606 529 603 503 604 531
607 501 602 533 601 507
600 533 601 507 601 534
598 510 600 1667 606 502
601 534 591 517 590 1676
594 515 595 543 588 1659
583 544 582 524 583 552
583 525 580 552 580 1664
577 1689 582 528 579 1687
579 1662 581 1687 583 1664
576
name key_8
9126 4434 600 532 610 516
574 539 610 484 612 524
613 497 602 534 596 512
601 534 610 496 601 541
587 619 480 1689 577 524
595 540 597 512 587 610
516 1668 591 532 591 1663
580 550 600 505 586 548
581 527 612 1638 602 516
593 1662 650 455 614 1657
602 1641 606 1653 647 1605
600
name key_9
9111 4402 658 467 683 475
580 507 626 503 588 547
601 504 607 541 591 517
579 575 579 508 571 564
587 520 686 1611 553 523
579 556 581 526 585 1684
797 1445 582 553 575 1663
584 550 578 527 586 552
574 533 583 549 581 526
582 1688 585 525 580 1682
587 1657 604 1661 691 1569
635
name key_0
9116 4412 632 497 626 482
634 502 624 481 629 512
626 477 621 513 617 490
609 525 618 490 608 525
612 517 590 1657 616 492
604 531 608 498 609 524
603 506 600 1667 602 1641
610 544 581 526 580 557
578 530 577 1673 597 1662
577 557 585 523 578 1669
601 1640 600 1676 604 1637
596
name key_red
9109 4440 598 526 620 485
608 535 592 544 564 529
610 500 659 482 600 505
601 534 599 528 583 531
598 510 599 1680 594 506
600 533 601 588 522 533
599 509 594 1674 598 1643
600 1664 600 512 590 544
594 513 597 1671 602 1640
597 537 587 520 612 523
592 1651 589 1673 595 1652
590
name key_green
9119 4409 629 504 631 477
627 507 627 483 620 513
627 481 618 515 614 500
600 530 601 504 612 521
608 501 605 1671 595 507
602 536 597 514 593 1665
603 506 600 1667 603 1639
605 1668 597 506 602 532
601 507 601 533 600 1642
599 538 597 508 599 542
592 1641 599 1669 600 1642
600
name key_yellow
9128 4419 609 530 606 497
608 526 605 502 605 530
604 504 603 532 602 505
602 533 601 507 600 531
604 507 599 1667 601 514
594 535 598 507 600 534
600 1644 596 538 597 1644
594 1689 578 534 569 547
589 520 578 1690 581 526
581 1693 573 530 574 580
555 1671 576 1686 577 1665
579
name key_blue
9117 4432 607 525 608 500
604 533 601 504 605 529
603 505 601 533 601 508
601 532 600 507 600 533
607 502 600 1668 600 507
599 536 600 508 598 536
593 1648 597 1671 598 1645
593 1675 593 514 596 538
596 511 593 1676 586 522
588 546 590 518 588 545
590 1651 584 1690 579 1657
588
name key_time
9120 4427 608 525 611 498
605 534 602 500 605 532
603 503 601 536 600 504
603 532 603 504 603 530
604 505 603 1669 598 507
608 528 598 507 601 1677
583 517 592 543 592 1650
592 1678 583 521 591 542
590 518 592 541 588 1658
578 1689 586 519 595 541
580 1669 572 1686 592 1650
589
name key_exit
9124 4379 652 483 645 461
646 488 639 474 631 498
634 474 629 505 631 477
630 505 628 479 629 506
627 481 627 1640 629 481
625 510 624 485 623 531
603 1637 604 1668 601 505
601 1667 602 506 601 532
602 505 602 1668 601 507
600 533 601 1641 601 533
602 1640 600 1669 605 1636
600
name key_left
9127 4416 611 520 615 494
609 528 602 503 611 525
603 505 602 531 603 505
602 532 602 506 604 529
603 506 601 1673 597 506
600 534 602 505 607 542
586 1640 601 534 600 514
593 1668 601 509 598 535
599 510 590 1676 596 511
600 1674 585 1653 594 539
597 1645 598 1670 585 1661
592
name key_up
9114 4439 601 526 605 502
605 530 603 505 603 530
603 506 601 533 601 512
596 532 622 485 602 532
601 507 602 1666 601 508
600 533 601 506 601 1669
595 512 598 536 602 510
594 1673 587 519 583 550
588 520 589 546 589 1650
587 1682 588 1657 598 534
585 1656 583 1685 589 1652
587
name key_down
9120 4405 629 520 614 489
616 583 549 498 607 528
606 503 630 510 599 516
593 600 530 506 600 535
600 520 589 1673 595 504
605 530 608 502 609 1665
594 503 625 1679 569 508
604 1690 576 506 606 526
601 508 606 528 607 1640
600 530 604 1652 594 523
605 1644 603 1662 596 1626
594
name key_right
9117 4424 619 518 612 497
606 537 599 504 600 530
606 501 613 522 603 504
602 532 602 506 603 531
602 506 601 1665 603 506
603 532 601 506 601 533
601 509 600 1665 602 508
600 1673 595 507 599 535
600 506 602 1667 601 1642
600 533 600 1644 599 534
600 1642 591 1675 601 1641
599
name key_ok
9114 4430 609 524 604 504
604 530 603 504 602 537
597 506 628 505 602 508
600 533 600 508 600 534
600 508 599 1668 596 513
597 537 596 512 598 1670
593 1647 593 543 594 519
586 1676 586 522 584 550
583 524 587 548 590 518
580 1692 572 1666 584 579
554 1659 580 1687 584 1662
583
name key_menu
9103 4435 602 550 579 498
603 579 552 510 599 532
605 504 600 533 599 571
565 507 600 506 602 535
601 505 653 1626 591 508
595 536 600 509 602 530
604 1663 622 1630 639 1600
598 530 723 404 570 549
586 521 594 1696 574 509
596 543 586 518 590 1678
595 1650 587 1686 645 1592
587
name key_volumeup
9131 4474 562 477 645 464
639 495 636 471 638 498
635 472 631 539 595 478
628 505 628 483 627 503
629 482 624 1737 533 480
627 507 627 488 624 1650
617 1624 612 1651 621 1617
625 1644 622 481 625 510
692 432 613 527 603 505
609 524 615 493 610 526
739 1506 607 1660 600 1645
606
name key_volumedown
9109 4411 625 511 612 498
615 519 614 500 612 522
613 498 597 534 605 531
572 536 599 510 596 538
594 507 601 1680 662 434
603 538 594 659 516 464
605 505 600 532 603 507
599 570 566 505 601 1664
603 527 579 1672 598 1644
598 1672 594 1651 595 1679
587 1648 594 530 601 1652
593
name key_next
9118 4399 641 518 615 465
643 601 531 462 639 502
630 480 626 506 627 485
628 501 629 614 501 504
625 491 662 1603 616 479
628 504 631 473 637 507
622 508 627 474 637 476
627 1676 600 477 624 539
596 508 598 1697 572 1644
632 1633 607 1619 625 528
605 1635 607 1637 641 1625
605
name key_previous
9107 4429 619 514 610 492
606 528 603 505 619 534
582 508 602 531 655 455
607 528 598 504 602 535
598 508 604 1670 700 404
595 539 597 507 606 1668
593 1646 597 1674 591 1657
593 530 592 521 587 544
586 552 564 564 571 514
582 556 582 523 577 1694
583 1657 581 1691 580 1705
542
name key_help
9139 4389 629 500 628 476
630 505 629 478 627 505
623 489 623 514 614 496
612 517 611 502 612 522
609 501 598 1666 610 503
594 539 593 514 596 1673
595 1651 592 1691 585 501
595 1676 601 503 634 500
597 511 597 538 595 533
568 568 570 1658 588 595
536 1669 573 1675 594 1666
575
name key_epg
9104 4405 633 491 633 496
611 522 607 501 635 678
432 500 604 521 621 496
601 535 600 504 608 528
601 506 633 1640 601 504
605 570 563 506 603 1663
614 1625 606 526 628 1616
608 1662 606 500 607 528
603 504 607 526 606 506
603 1662 610 513 579 538
604 1642 590 1673 596 1651
603
name key_sysrq
9123 4383 651 483 645 459
641 494 637 501 604 500
629 484 630 498 630 499
653 501 597 479 626 651
486 500 598 1666 607 506
598 558 581 506 588 1675
608 504 598 535 598 512
595 538 597 506 601 1669
598 504 600 531 600 1647
597 1693 577 1647 600 1670
603 1638 596 538 640 1604
594
end raw_codes
end remote
#!/bin/sh
# This is a modded script from init.d!!!
# Will start radio.py on boot
### BEGIN INIT INFO
# Provides: mpd
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: autofs $network $named alsa-utils pulseaudio
# Should-Stop: autofs $network $named alsa-utils pulseaudio
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Music Player Daemon
# Description: Start the Music Player Daemon (MPD) service
# for network access to the local audio queue.
### END INIT INFO
. /lib/lsb/init-functions
PATH=/sbin:/bin:/usr/sbin:/usr/bin
NAME=mpd
DESC="Music Player Daemon"
DAEMON=/usr/bin/mpd
MPDCONF=/etc/mpd.conf
START_MPD=true
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
if [ -n "$MPD_DEBUG" ]; then
set -x
MPD_OPTS=--verbose
fi
if [ ! -d "/var/run/mpd" ]; then
mkdir /var/run/mpd
if dpkg-statoverride --list --quiet /var/run/mpd > /dev/null; then
#if dpkg-statoverride is used update it with permissions there
dpkg-statoverride --force --quiet --update --add $( dpkg-statoverride --list --quiet /var/run/mpd ) 2> /dev/null
else
#use defaults
chown mpd:audio /var/run/mpd
chmod 755 /var/run/mpd
fi
fi
DBFILE=$(sed -n 's/^[[:space:]]*db_file[[:space:]]*"\?\([^"]*\)\"\?/\1/p' $MPDCONF)
PIDFILE=$(sed -n 's/^[[:space:]]*pid_file[[:space:]]*"\?\([^"]*\)\"\?/\1/p' $MPDCONF)
mpd_start () {
if [ "$START_MPD" != "true" ]; then
log_action_msg "Not starting MPD: disabled by /etc/default/$NAME".
exit 0
fi
log_daemon_msg "Starting $DESC" "$NAME"
if [ -z "$PIDFILE" -o -z "$DBFILE" ]; then
log_failure_msg \
"$MPDCONF must have db_file and pid_file set; cannot start daemon."
exit 1
fi
PIDDIR=$(dirname "$PIDFILE")
if [ ! -d "$PIDDIR" ]; then
mkdir -m 0755 $PIDDIR
chown mpd:audio $PIDDIR
fi
start-stop-daemon --start --quiet --oknodo --pidfile "$PIDFILE" \
--exec "$DAEMON" -- $MPD_OPTS "$MPDCONF"
python /radio.py &
log_end_msg $?
}
mpd_stop () {
if [ "$START_MPD" != "true" ]; then
log_failure_msg "Not stopping MPD: disabled by /etc/default/$NAME".
exit 0
fi
if [ -z "$PIDFILE" ]; then
log_failure_msg \
"$MPDCONF must have pid_file set; cannot stop daemon."
exit 1
fi
log_daemon_msg "Stopping $DESC" "$NAME"
start-stop-daemon --stop --quiet --oknodo --retry 5 --pidfile "$PIDFILE" \
--exec $DAEMON
log_end_msg $?
}
# note to self: don't call the non-standard args for this in
# {post,pre}{inst,rm} scripts since users are not forced to upgrade
# /etc/init.d/mpd when mpd is updated
case "$1" in
start)
mpd_start
;;
stop)
mpd_stop
;;
status)
status_of_proc -p $PIDFILE $DAEMON $NAME
;;
restart|force-reload)
mpd_stop
mpd_start
;;
force-start)
mpd_start
;;
force-restart)
mpd_stop
mpd_start
;;
force-reload)
mpd_stop
mpd_start
;;
*)
echo "Usage: $0 {start|start-create-db|stop|restart|force-reload}"
exit 2
;;
esac
# An example configuration file for MPD
# See the mpd.conf man page for a more detailed description of each parameter.
# Files and directories #######################################################
#
# This setting controls the top directory which MPD will search to discover the
# available audio files and add them to the daemon's online database. This
# setting defaults to the XDG directory, otherwise the music directory will be
# be disabled and audio files will only be accepted over ipc socket (using
# file:// protocol) or streaming files over an accepted protocol.
#
music_directory "/var/lib/mpd/music"
#
# This setting sets the MPD internal playlist directory. The purpose of this
# directory is storage for playlists created by MPD. The server will use
# playlist files not created by the server but only if they are in the MPD
# format. This setting defaults to playlist saving being disabled.
#
playlist_directory "/var/lib/mpd/playlists"
#
# This setting sets the location of the MPD database. This file is used to
# load the database at server start up and store the database while the
# server is not up. This setting defaults to disabled which will allow
# MPD to accept files over ipc socket (using file:// protocol) or streaming
# files over an accepted protocol.
#
db_file "/var/lib/mpd/tag_cache"
#
# These settings are the locations for the daemon log files for the daemon.
# These logs are great for troubleshooting, depending on your log_level
# settings.
#
# The special value "syslog" makes MPD use the local syslog daemon. This
# setting defaults to logging to syslog, otherwise logging is disabled.
#
log_file "/var/log/mpd/mpd.log"
#
# This setting sets the location of the file which stores the process ID
# for use of mpd --kill and some init scripts. This setting is disabled by
# default and the pid file will not be stored.
#
pid_file "/var/run/mpd/pid"
#
# This setting sets the location of the file which contains information about
# most variables to get MPD back into the same general shape it was in before
# it was brought down. This setting is disabled by default and the server
# state will be reset on server start up.
#
state_file "/var/lib/mpd/state"
#
# The location of the sticker database. This is a database which
# manages dynamic information attached to songs.
#
sticker_file "/var/lib/mpd/sticker.sql"
#
###############################################################################
# General music daemon options ################################################
#
# This setting specifies the user that MPD will run as. MPD should never run as
# root and you may use this setting to make MPD change its user ID after
# initialization. This setting is disabled by default and MPD is run as the
# current user.
#
user "mpd"
#
# This setting specifies the group that MPD will run as. If not specified
# primary group of user specified with "user" setting will be used (if set).
# This is useful if MPD needs to be a member of group such as "audio" to
# have permission to use sound card.
#
#group "nogroup"
#
# This setting sets the address for the daemon to listen on. Careful attention
# should be paid if this is assigned to anything other then the default, any.
# This setting can deny access to control of the daemon. Choose any if you want
# to have mpd listen on every address
#
# For network
bind_to_address "localhost"
#
# And for Unix Socket
#bind_to_address "/var/run/mpd/socket"
#
# This setting is the TCP port that is desired for the daemon to get assigned
# to.
#
#port "6600"
#
# This setting controls the type of information which is logged. Available
# setting arguments are "default", "secure" or "verbose". The "verbose" setting
# argument is recommended for troubleshooting, though can quickly stretch
# available resources on limited hardware storage.
#
#log_level "default"
#
# If you have a problem with your MP3s ending abruptly it is recommended that
# you set this argument to "no" to attempt to fix the problem. If this solves
# the problem, it is highly recommended to fix the MP3 files with vbrfix
# (available as vbrfix in the debian archive), at which
# point gapless MP3 playback can be enabled.
#
#gapless_mp3_playback "yes"
#
# This setting enables MPD to create playlists in a format usable by other
# music players.
#
#save_absolute_paths_in_playlists "no"
#
# This setting defines a list of tag types that will be extracted during the
# audio file discovery process. Optionally, 'comment' can be added to this
# list.
#
#metadata_to_use "artist,album,title,track,name,genre,date,composer,performer,disc"
#
# This setting enables automatic update of MPD's database when files in
# music_directory are changed.
#
#auto_update "yes"
#
# Limit the depth of the directories being watched, 0 means only watch
# the music directory itself. There is no limit by default.
#
#auto_update_depth "3"
#
###############################################################################
# Symbolic link behavior ######################################################
#
# If this setting is set to "yes", MPD will discover audio files by following
# symbolic links outside of the configured music_directory.
#
#follow_outside_symlinks "yes"
#
# If this setting is set to "yes", MPD will discover audio files by following
# symbolic links inside of the configured music_directory.
#
#follow_inside_symlinks "yes"
#
###############################################################################
# Zeroconf / Avahi Service Discovery ##########################################
#
# If this setting is set to "yes", service information will be published with
# Zeroconf / Avahi.
#
#zeroconf_enabled "yes"
#
# The argument to this setting will be the Zeroconf / Avahi unique name for
# this MPD server on the network.
#
#zeroconf_name "Music Player"
#
###############################################################################
# Permissions #################################################################
#
# If this setting is set, MPD will require password authorization. The password
# can setting can be specified multiple times for different password profiles.
#
#password "password@read,add,control,admin"
#
# This setting specifies the permissions a user has who has not yet logged in.
#
#default_permissions "read,add,control,admin"
#
###############################################################################
# Input #######################################################################
#
input {
plugin "curl"
proxy "127.0.0.1:8080"
# proxy_user "user"
# proxy_password "password"
}
#
###############################################################################
# Audio Output ################################################################
#
# MPD supports various audio output types, as well as playing through multiple
# audio outputs at the same time, through multiple audio_output settings
# blocks. Setting this block is optional, though the server will only attempt
# autodetection for one sound card.
#
# See <http://mpd.wikia.com/wiki/Configuration#Audio_Outputs> for examples of
# other audio outputs.
#
# An example of an ALSA output:
#
audio_output {
type "alsa"
name "My ALSA Device"
device "hw:0,0" # optional
format "44100:16:2" # optional
mixer_device "default" # optional
mixer_control "PCM" # optional
mixer_index "0" # optional
}
#
# An example of an OSS output:
#
#audio_output {
# type "oss"
# name "My OSS Device"
# device "/dev/dsp" # optional
# format "44100:16:2" # optional
# mixer_device "/dev/mixer" # optional
# mixer_control "PCM" # optional
#}
#
# An example of a shout output (for streaming to Icecast):
#
#audio_output {
# type "shout"
# encoding "ogg" # optional
# name "My Shout Stream"
# host "localhost"
# port "8000"
# mount "/mpd.ogg"
# password "hackme"
# quality "5.0"
# bitrate "128"
# format "44100:16:1"
# protocol "icecast2" # optional
# user "source" # optional
# description "My Stream Description" # optional
# genre "jazz" # optional
# public "no" # optional
# timeout "2" # optional
#}
#
# An example of a recorder output:
#
#audio_output {
# type "recorder"
# name "My recorder"
# encoder "vorbis" # optional, vorbis or lame
# path "/var/lib/mpd/recorder/mpd.ogg"
## quality "5.0" # do not define if bitrate is defined
# bitrate "128" # do not define if quality is defined
# format "44100:16:1"
#}
#
# An example of a httpd output (built-in HTTP streaming server):
#
#audio_output {
# type "httpd"
# name "My HTTP Stream"
# encoder "vorbis" # optional, vorbis or lame
# port "8000"
# quality "5.0" # do not define if bitrate is defined
# bitrate "128" # do not define if quality is defined
# format "44100:16:1"
#}
#
# An example of a pulseaudio output (streaming to a remote pulseaudio server)
#
#audio_output {
# type "pulse"
# name "My Pulse Output"
# server "remote_server" # optional
# sink "remote_server_sink" # optional
#}
#
## Example "pipe" output:
#
#audio_output {
# type "pipe"
# name "my pipe"
# command "aplay -f cd 2>/dev/null"
## Or if you're want to use AudioCompress
# command "AudioCompress -m | aplay -f cd 2>/dev/null"
## Or to send raw PCM stream through PCM:
# command "nc example.org 8765"
# format "44100:16:2"
#}
#
## An example of a null output (for no audio output):
#
#audio_output {
# type "null"
# name "My Null Output"
#}
audio_output {
type "fifo"
name "FM_fifo"
path "/tmp/mpd.fifo"
format "44100:16:2"
}
#
# This setting will change all decoded audio to be converted to the specified
# format before being passed to the audio outputs. By default, this setting is
# disabled.
#
#audio_output_format "44100:16:2"
#
# If MPD has been compiled with libsamplerate support, this setting specifies
# the sample rate converter to use. Possible values can be found in the
# mpd.conf man page or the libsamplerate documentation. By default, this is
# setting is disabled.
#
#samplerate_converter "Fastest Sinc Interpolator"
#
###############################################################################
# Volume control mixer ########################################################
#
# These are the global volume control settings. By default, this setting will
# be detected to the available audio output device, with preference going to
# hardware mixing. Hardware and software mixers for individual audio_output
# sections cannot yet be mixed.
#
# An example for controlling an ALSA, OSS or Pulseaudio mixer; If this
# setting is used other sound applications will be affected by the volume
# being controlled by MPD.
#
#mixer_type "hardware"
#
# An example for controlling all mixers through software. This will control
# all controls, even if the mixer is not supported by the device and will not
# affect any other sound producing applications.
#
#mixer_type "software"
#
# This example will not allow MPD to touch the mixer at all and will disable
# all volume controls.
#
#mixer_type "disabled"
#
###############################################################################
# Normalization automatic volume adjustments ##################################
#
# This setting specifies the type of ReplayGain to use. This setting can have
# the argument "album" or "track". See <http://www.replaygain.org> for more
# details. This setting is disabled by default.
#
#replaygain "album"
#
# This setting sets the pre-amp used for files that have ReplayGain tags. By
# default this setting is disabled.
#
#replaygain_preamp "0"
#
# This setting enables on-the-fly normalization volume adjustment. This will
# result in the volume of all playing audio to be adjusted so the output has
# equal "loudness". This setting is disabled by default.
#
#volume_normalization "no"
#
###############################################################################
# MPD Internal Buffering ######################################################
#
# This setting adjusts the size of internal decoded audio buffering. Changing
# this may have undesired effects. Don't change this if you don't know what you
# are doing.
#
#audio_buffer_size "2048"
#
# This setting controls the percentage of the buffer which is filled before
# beginning to play. Increasing this reduces the chance of audio file skipping,
# at the cost of increased time prior to audio playback.
#
#buffer_before_play "10%"
#
###############################################################################
# Resource Limitations ########################################################
#
# These settings are various limitations to prevent MPD from using too many
# resources. Generally, these settings should be minimized to prevent security
# risks, depending on the operating resources.
#
#connection_timeout "60"
#max_connections "10"
#max_playlist_length "16384"
#max_command_list_size "2048"
#max_output_buffer_size "8192"
#
###############################################################################
# Character Encoding ##########################################################
#
# If file or directory names do not display correctly for your locale then you
# may need to modify this setting. After modification of this setting mpd
# --create-db must be run to change the database.
#
filesystem_charset "UTF-8"
#
# This setting controls the encoding that ID3v1 tags should be converted from.
#
id3v1_encoding "UTF-8"
#
###############################################################################
# SIDPlay decoder #############################################################
#
# songlength_database:
# Location of your songlengths file, as distributed with the HVSC.
# The sidplay plugin checks this for matching MD5 fingerprints.
# See http://www.c64.org/HVSC/DOCUMENTS/Songlengths.faq
#
# default_songlength:
# This is the default playing time in seconds for songs not in the
# songlength database, or in case you're not using a database.
# A value of 0 means play indefinitely.
#
# filter:
# Turns the SID filter emulation on or off.
#
#decoder {
# plugin "sidplay"
# songlength_database "/media/C64Music/DOCUMENTS/Songlengths.txt"
# default_songlength "120"
# filter "true"
#}
#
###############################################################################
begin
prog = radio
button = key_wakeup
config = pwron
repeat = 0
end
begin
prog = radio
button = KEY_UP
config = up
repeat = 1
end
begin
prog = radio
button = KEY_DOWN
config = down
repeat = 1
end
begin
prog = radio
button = KEY_LEFT
config = left
repeat = 1
end
begin
prog = radio
button = KEY_RIGHT
config = right
repeat = 1
end
begin
prog = radio
button = KEY_MENU
config = menu
repeat = 0
end
begin
prog = radio
button = KEY_TIME
config = time
repeat = 0
end
begin
prog = radio
button = KEY_RED
config = red
repeat = 0
end
begin
prog = radio
button = KEY_GREEN
config = green
repeat = 0
end
begin
prog = radio
button = KEY_YELLOW
config = yellow
repeat = 0
end
begin
prog = radio
button = KEY_BLUE
config = blue
repeat = 0
end
begin
prog = radio
button = KEY_EXIT
config = exit
repeat = 0
end
begin
prog = radio
button = KEY_OK
config = ok
repeat = 0
end
begin
prog = radio
button = KEY_HELP
config = help
repeat = 0
end
begin
prog = radio
button = KEY_PREVIOUS
config = prev
repeat = 0
end
begin
prog = radio
button = KEY_NEXT
config = next
repeat = 0
end
begin
prog = radio
button = KEY_MUTE
config = mute
repeat = 0
end
begin
prog = radio
button = KEY_VOLUMEUP
config = volup
repeat = 0
end
begin
prog = radio
button = KEY_VOLUMEDOWN
config = voldn
repeat = 0
end
begin
prog = radio
button = KEY_SYSRQ
config = rcl
repeat = 0
end
begin
prog = radio
button = KEY_0
config = 0
repeat = 0
end
begin
prog = radio
button = KEY_1
config = 1
repeat = 0
end
begin
prog = radio
button = KEY_2
config = 2
repeat = 0
end
begin
prog = radio
button = KEY_3
config = 3
repeat = 0
end
begin
prog = radio
button = KEY_4
config = 4
repeat = 0
end
begin
prog = radio
button = KEY_5
config = 5
repeat = 0
end
begin
prog = radio
button = KEY_6
config = 6
repeat = 0
end
begin
prog = radio
button = KEY_7
config = 7
repeat = 0
end
begin
prog = radio
button = KEY_8
config = 8
repeat = 0
end
begin
prog = radio
button = KEY_9
config = 9
repeat = 0
end
#!/usr/bin/python
# -*- coding: utf-8 -*-
from adaptive_gen import *
import wiringpi2 as w # For LED control
import pywapi as weather # for weather
import smbus, time, datetime, pdb, os,sys, alsaaudio, subprocess, lirc, atexit, signal, audioop,errno,math, re, threading, copy # For the rest
import pykakasi.kakasi as kakasi
from leds import *
from mpd import MPDClient # For media control
global cli, bus, mix, remote
from shairportdecoder.decoder import Processor
from shairportdecoder.metadata import Infos
from shairportdecoder import decoder
mustEnterAirport = False
airportInfoLine = u""
airportInfoUpdate = datetime.datetime.now()
airportInfoChanged = False
airportIgnoreNextState = False
def AirportGoes(event_type, info):
global mustEnterAirport
global airportIgnoreNextState
global globalBreaker
if event_type == decoder.CONNECTED:
#print("PBEG oelutz")
mustEnterAirport = True
globalBreaker = True
airportIgnoreNextState = True
elif event_type == decoder.STATE:
if not (info.playstate == Infos.PLAYING) and not airportIgnoreNextState:
mustEnterAirport = False
elif (info.playstate == Infos.PLAYING):
airportIgnoreNextState = True #workaround for a bug in api
elif airportIgnoreNextState:
airportIgnoreNextState = False
def AirportEvent(event_type, info):
global airportInfoLine
global airportInfoUpdate
global airportInfoChanged
assert(isinstance(info, Infos))
if event_type == decoder.VOLUME:
pass
elif event_type == decoder.COVERART:
pass
elif event_type == decoder.META:
if info.itemname is not None:
airportInfoLineTemp = japToAscii((info.songartist + " - " if info.songartist else "") + (info.itemname if info.itemname else "Unknown Track"))
if not (airportInfoLine == airportInfoLineTemp):
airportInfoLine = airportInfoLineTemp
#print airportInfoLine
airportInfoChanged = True
airportInfoUpdate = datetime.datetime.now()
#print "New meta"
#print "NAMELEN", len(info.itemname)
#print("Got Metadata,\n{meata}".format(meata=airportInfoLine)) # lol, meat typo.
elif event_type == decoder.STATE:
#print("State changed to {sas}".format(sas=info.playstate))
pass
kakasi = kakasi()
kakasi.setMode("H","a") # default: Hiragana no convert
kakasi.setMode("K","a") # default: Katakana no convert
kakasi.setMode("J","a") # default: Japanese no convert
kakasi.setMode("E","a") # default: Symbols no convert
kakasi.setMode("r","Hepburn") # default: use Hepburn Roman table
kakasi.setMode("s", True) # separate, default: no Separator
kakasi.setMode("C", True) # capitalize default: no Capitalize
kakaconv = kakasi.getConverter()
kakare = re.compile(ur"([\u3000-\u303F]|[\u3040-\u309F]|[\u30A0-\u30FF]|[\uFF00-\uFFEF]|[\u4E00-\u9FAF]|[\u2605-\u2606]|[\u2190-\u2195]|\u203B)+")
russTable = {u'а': u'a',u'б': u'b',u'в': u'v',u'г': u'g',u'д': u'd',u'е': u'e',u'ё': u'e',u'ж': u'zh',u'з': u'z',u'и': u'i',u'й': u'y',u'к': u'k',u'л': u'l',u'м': u'm',u'н': u'n',u'о': u'o',u'п': u'p',u'р': u'r',u'с': u's',u'т': u't',u'у': u'u',u'ф': u'f',u'х': u'h',u'ц': u'ts',u'ч': u'ch',u'ш': u'sh',u'щ': u'sch',u'ъ': u'',u'ы': u'y',u'ь': u'',u'э': u'e',u'ю': u'yu',u'я': u'ya',u'А': u'A',u'Б': u'B',u'В': u'V',u'Г': u'G',u'Д': u'D',u'Е': u'E',u'Ё': u'E',u'Ж': u'Zh',u'З': u'Z',u'И': u'I',u'Й': u'Y',u'К': u'K',u'Л': u'L',u'М': u'M',u'Н': u'N',u'О': u'O',u'П': u'P',u'Р': u'R',u'С': u'S',u'Т': u'T',u'У': u'U',u'Ф': u'F',u'Х': u'H',u'Ц': u'Ts',u'Ч': u'Ch',u'Ш': u'Sh',u'Щ': u'Sch',u'Ъ': u'',u'Ы': u'Y',u'Ь': u'',u'Э': u'E',u'Ю': u'Yu',u'Я': u'Ya'}
def checkJap(string):
return (kakare.match(string) != None)
def japToAscii(string):
global russTable
try:
for letter, transcription in russTable.iteritems():
string = string.replace(letter,transcription)
except:
pass
return kakaconv.do(string)
WEATHER_CITY='RSXX0111'
didUpdateTable = False
global didUpdateTable
def getNewBrightnessTable():
global adaptiveBrightnessTable
print "Current brightness table:"
printTable(adaptiveBrightnessTable)
try:
result = weather.get_weather_from_weather_com(WEATHER_CITY, 'metric')
result = result['forecasts'][0]
print "Sunrise: ",result['sunrise']
print "Sunset: ",result['sunset']
adaptiveBrightnessTable = generateTable(result['sunrise'],result['sunset'])
print "Got new brightness table:"
printTable(adaptiveBrightnessTable)
except:
print "Error getting new brightness table"
adaptiveBrightnessTable = [2, # 12 am
2, # 1am
2, # 2am
2, # 3am
2, # 4am
2, # 5am
2, # 6am
3, # 7am
4, # 8am
4, # 9am
5, # 10am
6, # 11am
7, # 12am
7, # 1pm
7, # 2pm
7, # 3pm
7, # 4pm
7, # 5pm
6, # 6pm
6, # 7pm
6, # 8pm
5, # 9pm
4, # 10pm
3] # 11pm
hrs = 0
global hrs
def updateHrs():
now = datetime.datetime.now()
hrs = now.strftime("%H")
min = now.strftime("%M")
global didUpdateTable
if int(hrs) == 0 and int(min) == 0 and not didUpdateTable:
didUpdateTable = True
getNewBrightnessTable()
elif int(hrs) == 0 and int(min) > 0 and didUpdateTable:
didUpdateTable = False
# ============ Connect to MPD as player ============
cli = MPDClient()
cli.timeout = 10
cli.idletimeout = None
# ============ Open Mixer =============
mix = alsaaudio.Mixer('PCM')
mix.setvolume(96)
# ============ Open Remote =============
remote = lirc.init('radio', '/radio.lirc')
lirc.set_blocking(False, remote)
# =========== Open I2c bus =============
bus = smbus.SMBus(1)
w.wiringPiSetupGpio()
global UP_BTN_PIN, DN_BTN_PIN, PW_BTN_PIN, AV_BTN_PIN, PW_LED_PIN, YE_LED_PIN, GR_LED_PIN, ANT_SELECT_PIN
UP_BTN_PIN = 24
DN_BTN_PIN = 23
PW_BTN_PIN = 22
AV_BTN_PIN = 27
ANT_SELECT_PIN = 17
RELAY_SIMULATE_PIN = 7
# ======== Set pin modes ==========
# Power Led
pwr = LED(PW_PIN)
# Yellow Led
yel = LED(YE_PIN)
# Green Led
grn = LED(GR_PIN)
w.pinMode(UP_BTN_PIN, 0)
w.pinMode(DN_BTN_PIN, 0)
w.pinMode(PW_BTN_PIN, 0)
w.pinMode(AV_BTN_PIN, 0)
w.pinMode(ANT_SELECT_PIN, 1)
w.pinMode(RELAY_SIMULATE_PIN, 1)
def selectAntenna(toGpio):
w.digitalWrite(ANT_SELECT_PIN, not toGpio)
def clickRelay(toOn):
w.digitalWrite(RELAY_SIMULATE_PIN, not toOn)
# Connect antenna to default destination
selectAntenna(False)
clickRelay(False)
# ENABLE PULL UP RESISTORS ON BUTTONS
w.pullUpDnControl(UP_BTN_PIN, 2)
w.pullUpDnControl(DN_BTN_PIN, 2)
w.pullUpDnControl(AV_BTN_PIN, 2)
w.pullUpDnControl(PW_BTN_PIN, 2)
globalBreaker = False
# DISPLAY CONTROLLER INITIALIZATION
global addr,cmd,val
addr = 0x38 # That's what it was for me at least
cmd = 0x00
val = 0x27
bus.write_byte_data(addr, cmd, val)
def dispBright(level): # Set brightness to level of 0 to 7
if level > 7:
level = 7
if level < 0:
level = 0
lvls = ['000','001','010','011','100','101','110','111']
val = int('0'+lvls[level]+'0111',2)
bus.write_byte_data(addr,cmd,val)
def bright(): # Set brightness to max
dispBright(7)
def mid(): # Set brightness to medium
dispBright(5)
def low(): # Lowest brightness, hardly visible in daylight
dispBright(3)
global point
point =0 # This is for the clock dot thing
# Handy methods for button reading
def pwrBtn():
return not w.digitalRead(22)
def modeBtn():
return not w.digitalRead(27)
def upBtn():
return not w.digitalRead(24)
def downBtn():
return not w.digitalRead(23)
# This converts numbers into codes for the SAA chip
def numToSeg(num, dotted=0):
retv = 0x00
chars = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F]
if num > 9:
num = 9
if num < 0:
num = 0
retv = chars[num]
if dotted == 1:
retv = retv + 0x80
return retv
charmap = { '0': numToSeg(0),
'1':numToSeg(1),
'2':numToSeg(2),
'3':numToSeg(3),
'4':numToSeg(4),
'5':numToSeg(5),
'6':numToSeg(6),
'7':numToSeg(7),
'8':numToSeg(8),
'9':numToSeg(9),
'':0x00, ' ':0x00,
'a':0x77,
'b':0x7c,
'c':0x39,
'd':0x5e,
'e':0x79,
'f':0x71,
'g':0x3d ,
'h': 0x74,
'i':0x04,
'j': 0x1E ,
'k':0x75,
'l':0x38,
'm':0x54,
'n':0x54,
'o': 0x5c,
'p':0x73,
'q':0x67 ,
'r': 0x50,
's': numToSeg(5),
't':0x78 ,
'u':0x1c,
'v':0x1c,
'w':0x7e,
'x':0x76,
'y':0x6e,
'z':0x1B,
'-': 0x40, '_': 0x08,
'A':0x77,
'B':0x7c,
'C':0x39,
'D':0x5e,
'E':0x79,
'F':0x71,
'G':0x3d,
'H':0x74,
'I': numToSeg(1),
'J': 0x1E,
'K': 0x75,
'L': 0x38,
'M': 0x37,
'N': 0x54,
'O': numToSeg(0),
'P': 0x73,
'Q': 0x67,
'R': 0x50,
'S': numToSeg(5),
'T': 0x78,
'U': 0x3E,
'V': 0x3E,
'W': 0x7e,
'X': 0x76,
'Y': 0x6e,
'Z':0x1B,
'(':0x21, '[':0x21, '"':0x22,
')':0x0C, ']':0x0C,
u'º':0x63,
'.':0x80
}
# This is the same but also has some characters too
def charToSeg(char, dotted=0):
retv = 0x00
global charmap
chars = charmap
try:
retv=chars[char]
retv = retv + (0x80 * dotted)
return retv
except:
return 0x00 + (0x80 * dotted)
curScreen = [0x00,0x00,0x00,0x00]
# This writes 4 symbol codes into the SAA bus
def writeAll(c1,c2,c3,c4):
global curScreen
if curScreen[0] != c1:
cmd = 0x01
val = c1
bus.write_byte_data(addr,cmd,val)
curScreen[0] = c1
if curScreen[1] != c2:
cmd = 0x02
val = c2
bus.write_byte_data(addr,cmd,val)
curScreen[1] = c2
if curScreen[2] != c3:
cmd = 0x03
val = c3
bus.write_byte_data(addr,cmd,val)
curScreen[2] = c3
if curScreen[3] != c4:
cmd = 0x04
val = c4
bus.write_byte_data(addr,cmd,val)
curScreen[3] = c4
updateHrs()
def writeFrame(frame):
writeAll(frame[0],frame[1],frame[2],frame[3])
def makeStringFrame(msg=' ',d1=0,d2=0,d3=0,d4=0):
if len(msg) < 5:
msg = msg + ' '
return [charToSeg(msg[0], dotted=d1), charToSeg(msg[1], dotted=d2), charToSeg(msg[2], dotted=d3), charToSeg(msg[3], dotted=d4)]
# This writes 4 symbols, d1 d2 d3 and d4 are dots after the respective symbols
def writeStr(msg = ' ',d1=0, d2=0,d3=0,d4=0):
writeFrame(makeStringFrame(msg,d1,d2,d3,d4))
# Says what it does: make a string with enough lead zeroes to display it on the front panel
def intToStrLeadZero(num):
if num < 10:
return '000'+str(num)
elif num < 100:
return '00'+str(num)
elif num < 1000:
return '0'+str(num)
else:
return str(num)
# ============================== MAIN RUN LOOP STARTS HERE ======================================
# Tell the user we are booting
dispBright(3)
writeStr('load')
# Connect to media player
cli.connect('localhost', 6600)
# Options for reconnect instead of next station
cli.single(1)
cli.repeat(1)
cli.consume(0)
getNewBrightnessTable()
# FIFO
fifo = os.open('/tmp/mpd.fifo', os.O_RDONLY)
def fallDigits(digits, reverse=False):
global curScreen
needTrans = False
for digit in range(0,4):
if (not (curScreen[digit] == digits[digit])) and not (abs(curScreen[digit] - digits[digit]) == 0x80):
needTrans = True
break
if not needTrans:
writeAll(digits[0],digits[1],digits[2],digits[3])
return
for frame in (range(0,4) if not reverse else list(reversed(range(0,4)))):
for digit in range(0,4):
if not (curScreen[digit] == digits[digit]):
# transition since it's not equal
newOne = 0x0
f = (curScreen[digit] if not reverse else digits[digit])
t = (digits[digit] if not reverse else curScreen[digit])
if (abs(f - t) == 0x80):
newOne = t
elif frame == 0:
newOne = f
elif frame == 1:
newOne = (4*((f&2)>0) +8*((f&64)>0) + 16*((f&32)>0) + 64*((f&1)>0) + 1 * ((t&8)>0))
elif frame == 2:
newOne = 2*((t&4)>0) + 64*((t&8)>0) + 32*((t&16)>0) + 1*((t&64)>0) + 8*((f&1)>0)
elif frame == 3:
newOne = t
writeAll((newOne if digit == 0 else curScreen[0]),(newOne if digit == 1 else curScreen[1]),(newOne if digit == 2 else curScreen[2]),(newOne if digit == 3 else curScreen[3]))
time.sleep(0.1)
# This is the clock 'thread' (it's all linear in fact lol)
def clock():
global point
global hrs
if point == 0:
point = 1
else:
point = 0
point = point or isFMCast # Low EMI mode
now = datetime.datetime.now()
hrs = now.strftime("%H")
min = now.strftime("%M")
# Would be nice to dim it at night, have it at mid in the morning and bright in the daytime
dispBright(adaptiveBrightnessTable[int(hrs)])
h_0 = int(hrs[0])
h_1 = int(hrs[1])
m_0 = int(min[0])
m_1 = int(min[1])
# Output 4 numbers
fallDigits([numToSeg(h_0), numToSeg(h_1, dotted=point), numToSeg(m_0), numToSeg(m_1)])
def transMessage(message,d1=0,d2=0,d3=0,d4=0):
global hrs
for i in range(0,7):
dispBright(7-i)
w.delay(50)
writeStr(message,d1,d2,d3,d4)
for i in range(0,7):
dispBright(i)
w.delay(50)
def transClock():
now = datetime.datetime.now()
hrs = now.strftime("%H")
mins = now.strftime("%M")
buildIn(hrs+mins)
# Vars for station and total number of them
global station, stationMax
station = int(cli.status()['song'])
stationMax = int(cli.status()['playlistlength'])-1
# Recording stuff
global isRecing, recStation, recLedSt, recorder
isRecing = 0
recStation = 0
recName = ''
recLedSt = 0
recorder = None
# Sleep timer stuff
global sleepEnabled, sleepBegan, sleepDur, powerIsOn
sleepEnabled = 0
sleepBegan = 0
sleepDur = 0
powerIsOn = 0
# Menu and clock mode stuff
global menu, clockOnPlayer
clockOnPlayer = 0
# ================== Record button or menu item function
def toggleRec():
global isRecing, recStation, recLedSt, recorder, recName
if isRecing == 0: # We aren't recording
recLedSt = 1 # Rec led state
recStation = station # Rec station Number
isRecing = 1 # is recording
cs = cli.currentsong()
if 'name' in cs:
recName = cs['name']
surl = cs['file'] # Get the stream URL
recorder = subprocess.Popen((['streamripper',surl,'-d','/recordings', '-u','vlc 1.1.0-git-20100330-0003','--quiet'])) # Start streamripper into /recordings
snake(1)
scrollMessage('recording strt', 0.1, holdOff=0.5, moveIn=True, makeBuildIn=False, fadeIn=True) # Tell the user that we start now
grn.setValue(100)
time.sleep(0.25)
else: # We are recording now
recorder.terminate() # Kill streamripper
snake(1)
scrollMessage('record stop', 0.1, holdOff=0.5, moveIn=True, makeBuildIn=False, fadeIn=True) # Tell the user that we start now
grn.setValue(0)
recLedSt = 0 # Reset some vars
recStation = 0
isRecing = 0
recName = ''
# ===================== Info menu item method
def about():
bright() # Full brightness
time.sleep(0.5)
splashAnim(step = 0.05)
writeStr('gen ')
time.sleep(0.3)
writeStr(' ji ')
time.sleep(0.3)
writeStr(' tsu')
time.sleep(0.9)
scrollMessage('gadget lab', 0.1, holdOff=0.2)
writeStr('0 ')
time.sleep(0.3)
writeStr(' 0 ')
time.sleep(0.3)
writeStr(' 1 ')
time.sleep(0.9)
writeStr(' ')
time.sleep(0.5)
# ==================== Next button method
def nextSt():
global cli, station, stationMax
try:
cli.next()
except: # This likes to crash sometimes so...
try:
cli.disconnect()
cli.connect('localhost', 6600)
cli.next()
except: # And when even that crashes...
writeStr('shit')
pwr.setValue(100)
yel.setValue(100)
grn.setValue(100)
time.sleep(1)
# Update display
station = int(cli.status()['song'])
stationMax = int(cli.status()['playlistlength'])-1
ststr = intToStrLeadZero(station+1)
if clockOnPlayer or isInVis:
writeStr(ststr)
else:
fallDigits([charToSeg(ststr[0]),charToSeg(ststr[1]),charToSeg(ststr[2]),charToSeg(ststr[3])])
if isRecing == 1: # Is recording
if recStation != station and grn.state != ST_BREATHE: # Recording NOT the station we're listening to
grn.startBreathing()
else: # Recording exactly what we're listening to
grn.setValue(100)
# ==================== Prev button method, see above
def prevSt():
global cli, station, stationMax
try:
cli.previous()
except:
try:
cli.disconnect()
cli.connect('localhost', 6600)
cli.previous()
except:
writeStr('shit')
pwr.setValue(100)
yel.setValue(100)
grn.setValue(100)
time.sleep(1)
station = int(cli.status()['song'])
stationMax = int(cli.status()['playlistlength'])-1
ststr = intToStrLeadZero(station+1)
if clockOnPlayer or isInVis:
writeStr(ststr)
else:
fallDigits([charToSeg(ststr[0]),charToSeg(ststr[1]),charToSeg(ststr[2]),charToSeg(ststr[3])], reverse=True)
if isRecing == 1: # Is recording
if recStation != station and grn.state != ST_BREATHE: # Recording NOT the station we're listening to
grn.startBreathing()
else: # Recording exactly what we're listening to
grn.setValue(100)
# =============== Weather disp
def showWeather():
#try:
result = weather.get_weather_from_weather_com(WEATHER_CITY, 'metric')
result = result['current_conditions']
rstr = str(result['temperature']) + u'ºC, '+result['text']
rstr = rstr.encode('utf-8')
scrollMessage(rstr, moveIn=False, makeBuildIn=True, holdOn=1)
#except:
# pass
# =============== Handy checking for two things that are used to power the thing on
def powerOnCondition():
pbtn = pwrBtn() # Get pwr button
rbtn = False
lcode = lirc.nextcode() # Get IR code
if len(lcode) > 0:
if lcode[0] == u'pwron': # If IR button is pressed
rbtn = True
else:
lcode = [' ']
if modeBtn() or lcode[0] == 'time':
dbgMenu()
elif lcode[0] == 'help' or upBtn():
showWeather()
elif downBtn() or lcode[0] == 'red':
fmRadio()
return pbtn or rbtn # Return this or that
# ============= Hacklet to get current IR code
def irCode():
lcode = lirc.nextcode() # Get code
if len(lcode) > 0: # We have one
pwr.blinkOnce()
return lcode[0] # Return code
return '' # No button was pressed if we end up here
# ============ Sleep mode menu thread
def sleepMenu():
global YE_LED_PIN, sleepEnabled, sleepBegan, sleepDur
modes = [0,1,5,30,60,90,120] # Sleep mode times presets
smode = 0 # Selected mode
buildIn('set ')
time.sleep(1)
ic = '' # IR codes will be read here
while not (modeBtn() or ic == 'ok'): # While not OK button or mode button
ic = irCode() # Read IR code
if smode == 0: # 0 minutes is in fact 'None'
writeStr('none')
else:
writeStr(str(modes[smode]) + 'm')
if upBtn() or ic == 'up': # Up button handling
smode = smode +1
if smode >= len(modes): # Menu is cycled
smode = 0
if downBtn() or ic == 'down': # Down button handling
smode = smode -1
if smode < 0:
smode = len(modes)-1
time.sleep(0.25) # Give the CPU a rest
if smode == 0: # User selected None
if sleepEnabled == 1: # if sleep mode was on, however
yel.setValue(0)
sleepEnabled = 0 # And reset the shit
sleepBegan = 0
sleepDur = 0
else: # User chose some mode
if sleepEnabled == 0: # if sleep mode was off, however
yel.setValue(100)
sleepEnabled = 1 # Set up some variables
sleepBegan = datetime.datetime.now()
sleepDur = modes[smode]
menu = ['disp', 'cloc', 'canc', 'info', 'slep', 'rec ', 'fm r', 'tran', 'nowp'] # This is top menu entries
# Display Clock Cancel About Sleep Record FM Radio FM Now
# Station# Display Menu This Mode Start/stop Transmit Playing
def topMenu():
global menu, clockOnPlayer
menuItem = 0 # cur sel item
transMessage('pref')
time.sleep(1)
a = irCode()
while not (modeBtn() or a == 'ok'):
a = irCode() # Read IR code
if a == 'menu': # Menu button on remote exits menu
menuItem = -1
break
writeStr(menu[menuItem]) # Display current item
if (downBtn() or a == 'down'): # Down button
menuItem = menuItem +1
if menuItem >= len(menu): # Menu is cycled
menuItem = 0
if (upBtn() or a == 'up'): # Up button
menuItem = menuItem -1
if menuItem < 0:
menuItem = len(menu)-1
time.sleep(0.2)
if menuItem == 0: # Display Station No.
clockOnPlayer = 0
elif menuItem == 1: # Display Clock While On
clockOnPlayer = 1
elif menuItem == 3: # About this software
about()
elif menuItem == 4:
sleepMenu()
elif menuItem == 5:
# record
toggleRec()
elif menuItem == 6:
fmRadio()
elif menuItem == 7:
fmCastOn()
elif menuItem == 8:
nowPlaying()
dbgmenu = ['reld', 'rebo', 'canc']
def dbgMenu():
global dbgmenu, clockOnPlayer
menuItem = 0 # cur sel item
transMessage('serv')
time.sleep(1)
a = irCode()
while not (modeBtn() or a == 'ok'):
a = irCode() # Read IR code
if a == 'menu': # Menu button on remote exits menu
menuItem = -1
break
writeStr(dbgmenu[menuItem]) # Display current item
if (downBtn() or a == 'down'): # Down button
menuItem = menuItem +1
if menuItem >= len(dbgmenu): # Menu is cycled
menuItem = 0
if (upBtn() or a == 'up'): # Up button
menuItem = menuItem -1
if menuItem < 0:
menuItem = len(dbgmenu)-1
time.sleep(0.2)
if menuItem == 0: # Display Station No.
pwr.setValue(0)
transMessage('rest')
try:
cli.stop()
cli.disconnect()
except:
pass
os.execl('/radio.py', '/usr/bin/python /radio.py')
os.exit()
elif menuItem == 1: # Display Clock While On
pwr.setValue(50)
transMessage('boot')
try:
cli.stop()
cli.disconnect()
except:
pass
os.execl('/sbin/reboot','/sbin/reboot')
os.exit()
@atexit.register
def onExit(): # If the system is going for a reboot this will be useful
pwr.setValue(0)
yel.setValue(0)
grn.setValue(0)
selectAntenna(False)
clickRelay(False)
if isRecing == 1: # Stop recorder if needed
toggleRec()
transMessage('boot') # Show 'boot' on display
# for better responsiveness in animations
def showAnimation(animation, loops=1, delay=0.1):
global globalBreaker, powerIsOn, mustEnterAirport
timerCounter = 0
for i in range(0,loops):
for frame in animation:
writeFrame(frame)
timerCounter = 0
while timerCounter < delay:
if powerIsOn == 1 and not mustEnterAirport:
irThread()
if globalBreaker:
return
timerCounter += 0.01
time.sleep(0.01)
def splashAnim(count=5, step = 0.3):
count = count & 0x0F
showAnimation([
[0x00,0x40,0x40,0x00],
[0x39,0x09,0x09,0x0F]
], count, step)
writeAll(0x00,0x00,0x00,0x00)
def snake(count=5, step = 0.1):
count = count & 0x0F
showAnimation([
[0x00,0x00,0x00,0x01],
[0x00,0x00,0x01,0x01],
[0x00,0x01,0x01,0x01],
[0x01,0x01,0x01,0x00],
[0x21,0x01,0x00,0x00],
[0x31,0x00,0x00,0x00],
[0x38,0x00,0x00,0x00],
[0x18,0x08,0x00,0x00],
[0x08,0x08,0x08,0x00],
[0x00,0x08,0x08,0x08],
[0x00,0x00,0x08,0x0C],
[0x00,0x00,0x00,0x0E],
[0x00,0x00,0x00,0x06],
[0x00,0x00,0x00,0x02],
[0x00,0x00,0x00,0x00]
], count, step)
def showPolyTransition(sourceMasks, destinationMasks, destinationScreen, simultaneous=True, delay=0.06):
frames = []
frame = []
sourceScreen = curScreen
if len(sourceMasks) != len(destinationMasks):
print "ShowPolyTransition: Malformed Transition Data, masks arrays are not of same length!"
return
if simultaneous:
# Generate all characters at the same time
for i in range(0, len(sourceMasks)):
frame = []
for j in range(0,4):
frame.append((sourceScreen[j] & sourceMasks[i]) | (destinationScreen[j] & destinationMasks[i]))
frames.append(frame)
else:
for j in range(0,4):
for i in range(0, len(sourceMasks)):
frame = copy.copy(sourceScreen)
frame[j] = ((sourceScreen[j] & sourceMasks[i]) | (destinationScreen[j] & destinationMasks[i]))
frames.append(frame)
sourceScreen = frame
showAnimation(frames, delay=delay)
def showTransition(masks, destinationScreen, simultaneous=True,delay=0.06):
destMasks = []
for mask in masks:
destMasks.append(~mask)
showPolyTransition(masks, destMasks, destinationScreen, simultaneous, delay)
def buildIn(message, barred=False, keepCurrent=True, simultaneous=True, delay=0.06):
masks = []
message += ' '
if barred:
masks = [0xFF, 0xCF, 0x86, 0x80, 0x0]
else:
masks = [0xFF,0x7F,0x3F,0x1F,0x0F,0x07,0x03,0x01,0x0]
showTransition(masks, makeStringFrame(message), simultaneous, delay)
def buildFill(message, direction=0, barred=False, simultaneous=True, delay=0.06):
buildIn('8888',direction,barred,True,simultaneous,delay)
buildIn(message,direction,barred,True,simultaneous,delay)
def scrollMessage(message, delay=0.3, reverse=False, holdOff=1, moveIn=False, fadeIn=False, makeBuildIn=True, holdOn=0, moveOut=False):
#if checkJap(message.decode('utf-8')):
message = japToAscii(message.decode('utf-8'))
#if checkJap(message):
message = japToAscii(message)
if moveOut:
message = message + ' '
if moveIn:
if fadeIn:
transMessage(' ')
mtemp = ' '+message[0]+message[1]+message[2]+ message[3]
for i in range(0,len(mtemp)-3):
writeStr(mtemp[i]+mtemp[i+1]+mtemp[i+2]+ mtemp[i+3])
irThread()
if globalBreaker:
return
time.sleep(delay)
elif fadeIn and makeBuildIn:
transMessage(' ')
buildIn(message)
elif fadeIn:
transMessage(message[0]+message[1]+message[2]+ message[3])
elif makeBuildIn:
buildIn(message)
time.sleep(holdOn)
for i in range(0,len(message)-3):
writeStr(message[i]+message[i+1]+message[i+2]+ message[i+3])
irThread()
if globalBreaker:
return
time.sleep(delay)
if reverse:
time.sleep(holdOff)
for i in reversed(range(0,len(message)-3)):
writeStr(message[i]+message[i+1]+message[i+2]+ message[i+3])
irThread()
if globalBreaker:
return
time.sleep(delay)
irThread()
if globalBreaker:
return
time.sleep(holdOff)
# MPC viso
visFillBar = ['00001000', '01001000', '01001001']
def visFillBarW(v):
v = int(v)
if v < 0:
v = 0
if v >= len(visFillBar):
v = len(visFillBar)-1
return int(visFillBar[v],2)
def visFrame():
try:
rawStream = os.read(fifo, 4096)
except OSError as err:
if err.errno == errno.EAGAIN or err.errno == errno.EWOULDBLOCK:
rawStream = None
else:
pass
if rawStream:
leftChannel = audioop.tomono(rawStream, 2, 1, 0)
rightChannel = audioop.tomono(rawStream, 2, 0, 1)
stereoPeak = audioop.max(rawStream, 2)
leftPeak = audioop.max(leftChannel, 2)
rightPeak = audioop.max(rightChannel, 2)
leftDB = 20 * math.log10(leftPeak) -74
rightDB = 20 * math.log10(rightPeak) -74
# print(rightPeak, leftPeak, rightDB, leftDB)
valR = math.floor( (rightDB) /20 *4) -1
valL = math.floor( (leftDB) /20 *4) -1
valC1 = 0.5*valR+(valL*valL)
valC2 = (valR*valR)+0.5*valL
# print (valL,valC1,valC2,valR)
valR = min(valR, len(visFillBar))
valL = min(valL, len(visFillBar))
valC1 = min(valC1, len(visFillBar))
valC2 = min(valC2, len(visFillBar))
writeAll( visFillBarW(valL)+0x80, visFillBarW(valC1),visFillBarW(valC2)+0x80, visFillBarW(valR) )
def nowPlaying():
csong = cli.currentsong()
global isRecing, recStation, station
if isRecing and recStation != station:
snake(1,0.05)
snum = str(recStation)
if not (recName == ''):
snum = snum + ' - '+recName
scrollMessage('recording station '+snum, 0.1, True, 0.5, False,True)
if not 'title' in csong:
return
scrollMessage(csong['title'], 0.2, True, 1)
scrollMessage(csong['name'], 0.2, True, 1)
buildIn(intToStrLeadZero(station+1))
global lastDispChangeDate, lastDispTag
lastDispChangeDate = datetime.datetime.now()
lastDispTag = csong['title']
fmFreq = 104.0
fmLower = 30.0
fmUpper = 2000.0
radioBreaker = False
fmCaster = None
isFMCast = False
rdsFifo = None
fmCastUpper = 110
fmCastLower = 80
fmCastFreq = 110
def fmCastOn():
if isFMCast:
return
global fmCaster, isFMCast, rdsFifo, fmCastFreq, fmCastLower, fmCastUpper
scrollMessage("input frequency then press ok", holdOn=0.5, delay=0.1)
code = ''
num = str(fmCastFreq)
digits = 0
dot = 3
while ((not code == 'ok')) :
writeStr(num,d1 = (1 == dot),d2 = (2 == dot), d3 = (3 == dot), d4=(4 == dot))
code = irCode()
if code.isdigit():
num = num + code
digits = digits + 1
elif code == 'left':
if dot > 2:
dot = dot - 1
elif code == 'right':
if dot < 3:
dot = dot + 1
elif code == 'exit':
num = ''
digits = 0
elif code == 'menu':
return
time.sleep(0.3)
fstr = ''
num = num + '0000'
if 2 == dot:
fstr = num[0] + num[1]+ '.'+num[2]+num[3]
elif 3 == dot:
fstr = num[0] + num[1]+ num[2]+'.'+num[3]
elif 4 == dot:
fstr = num[0] + num[1]+ num[2]+num[3]
fr = float(fstr)
if fr >= fmCastLower and fr <= fmCastUpper:
fmCastFreq = fr
else:
return
selectAntenna(True)
time.sleep(0.5)
fmCaster = subprocess.Popen('/fmcast 49500 '+str(fmCastFreq), stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
isFMCast = True
scrollMessage("tune to fm "+str(fmCastFreq), delay=0.2, holdOff=0.2)
pwr.setValue(30)
#rdsFifo = open('/tmp/rds.fifo', 'w')
time.sleep(1)
def fmCastOff():
if not isFMCast:
return
scrollMessage('reboot to off transmitter', delay=0.1)
os.system("reboot")
def fmRadio():
if isFMCast:
transMessage("cant", d3=1)
time.sleep(1)
return
since = -1
global fmFreq, fmLower, fmUpper, radioBreaker
wasConn = 1
try:
cli.stop()
cli.disconnect()
except:
pwr.setValue(50)
wasConn = 0
snake(2,0.1)
mix.setvolume(100)
scrollMessage('fm radio ', holdOff=0, delay=0.07)
sas = str(fmFreq)
pro = subprocess.Popen('/fmradio '+str(fmFreq)+'M', stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
transMessage(sas.replace('.',''),d1=0,d2=(sas[2] == '.'),d3=(sas[3] == '.'))
code = irCode()
favs = [104.0,
103.5, 104.0, 106.0,
88.1, 68.25, 104.0]
while ((not code == 'pwron') and (not pwrBtn()) ) and ((not code == 'menu') and (not modeBtn()) ):
# Run until power must be off or user exited
code = irCode()
if not ((not code == 'pwron') and (not pwrBtn()) ) or ((not code == 'menu') and (not modeBtn()) ):
if code == 'up' or code == 'next' or upBtn():
fmFreq = fmFreq + 0.5
if fmFreq > fmUpper:
fmFreq = fmLower
sas = str(fmFreq)
since = 0
writeStr(sas.replace('.',''),d1=0,d2=(sas[2] == '.'),d3=(sas[3] == '.'))
yel.setValue(50)
grn.setValue(0)
elif code == 'left':
fmFreq = fmFreq - 0.1
if fmFreq < fmLower:
fmFreq = fmUpper
sas = str(fmFreq)
since = 0
writeStr(sas.replace('.',''),d1=0,d2=(sas[2] == '.'),d3=(sas[3] == '.'))
yel.setValue(50)
grn.setValue(0)
elif code == 'right':
fmFreq = fmFreq + 0.1
if fmFreq > fmUpper:
fmFreq = fmLower
sas = str(fmFreq)
since = 0
writeStr(sas.replace('.',''),d1=0,d2=(sas[2] == '.'),d3=(sas[3] == '.'))
yel.setValue(50)
grn.setValue(0)
elif code == 'down' or code == 'prev' or downBtn():
fmFreq = fmFreq - 0.5
if fmFreq < fmLower:
fmFreq = fmUpper
sas = str(fmFreq)
since = 0
writeStr(sas.replace('.',''),d1=0,d2=(sas[2] == '.'),d3=(sas[3] == '.'))
yel.setValue(50)
grn.setValue(0)
elif code == 'ok' and since > -1:
since = 6
elif code.isdigit(): # Digit buttons
num = code
digits = 0
dot = 2
yel.setValue(50)
grn.setValue(0)
while (digits < 3) and (not code == 'ok'):
writeStr(num,d1 = (1 == dot),d2 = (2 == dot), d3 = (3 == dot), d4=(4 == dot))
code = irCode()
if code.isdigit():
num = num + code
digits = digits + 1
elif code == 'left':
if dot > 2:
dot = dot - 1
elif code == 'right':
if dot < 4:
dot = dot + 1
time.sleep(0.3)
yel.setValue(0, smooth=False)
grn.setValue(100, smooth=False)
fstr = ''
num = num + '0000'
if 2 == dot:
fstr = num[0] + num[1]+ '.'+num[2]+num[3]
elif 3 == dot:
fstr = num[0] + num[1]+ num[2]+'.'+num[3]
elif 4 == dot:
fstr = num[0] + num[1]+ num[2]+num[3]
fr = float(fstr)
if fr >= fmLower and fr <= fmUpper:
fmFreq = fr
os.killpg(pro.pid, signal.SIGTERM)
pro = subprocess.Popen('/fmradio '+str(fmFreq)+'M', stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
sas = str(fmFreq)
writeStr(sas.replace('.',''),d1=0,d2=(sas[2] == '.'),d3=(sas[3] == '.'))
grn.setValue(0, smooth=False)
elif code == 'yellow':
splashAnim(5, 0.1)
transMessage('scan')
grn.setValue(50, smooth=False)
code = irCode()
tmr = 0
while not (code == 'yellow' or code == 'menu' or code == 'ok'):
code = irCode()
tmr = tmr + 1
if tmr >= 6:
fmFreq = fmFreq + 0.5
if fmFreq > fmUpper:
fmFreq = fmLower
sas = str(fmFreq)
writeStr(sas.replace('.',''),d1=0,d2=(sas[2] == '.'),d3=(sas[3] == '.'))
os.killpg(pro.pid, signal.SIGTERM)
pro = subprocess.Popen('/fmradio '+str(fmFreq)+'M', stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
tmr = 0
time.sleep(0.5)
grn.setValue(0,smooth=False)
time.sleep(0.5)
if since > -1:
since = since +1
if since >= 6:
since = -1
yel.setValue(1)
os.killpg(pro.pid, signal.SIGTERM)
pro = subprocess.Popen('/fmradio '+str(fmFreq)+'M', stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
time.sleep(1)
yel.setValue(0)
grn.setValue(0)
radioBreaker = True
os.killpg(pro.pid, signal.SIGTERM)
mix.setmute(0)
#mix.setvolume(88)
if wasConn == 1:
cli.connect('localhost', 6600) # Set up media player
time.sleep(1)
cli.single(1)
cli.repeat(1)
cli.consume(0)
def airportMode():
clickRelay(True)
global mustEnterAirport
global airportInfoChanged
global airportInfoUpdate
global airportInfoLine
#print "Airport Mode"
scrollMessage("airport mode", delay=0.1, reverse=True, moveIn=True, fadeIn=True, makeBuildIn=False)
while mustEnterAirport:
if airportInfoChanged:
delta = datetime.datetime.now() - airportInfoUpdate
if delta.seconds >= 60*10 or delta.seconds > 3:
#print "NEW META DISP"
#print "METALEN", len(airportInfoLine)
airportInfoChanged = False
try:
snake(1)
if len(airportInfoLine) > 0:
scrollMessage(airportInfoLine, 0.1, True, 1, moveIn=True, fadeIn=False)
splashAnim(2)
except:
pass
time.sleep(0.5)
if pwrBtn() and modeBtn():
mustEnterAirport = False
writeStr('airp')
clickRelay(False)
writeStr(' ')
time.sleep(1)
# ======================= This is the IR scanner that runs in a While loop
def irThread():
global globalBreaker
global mustEnterAirport
lcode = lirc.nextcode() # Get code
if len(lcode) > 0: # We have a code
global lastDispChangeDate
lastDispChangeDate = datetime.datetime.now()
globalBreaker = True
if lcode[0] != 'pwron':
pwr.blinkOnce()
if lcode[0] == 'time': # Clock button, same as clock in menu
global clockOnPlayer
clockOnPlayer = not clockOnPlayer
if clockOnPlayer:
transClock()
else:
transMessage(intToStrLeadZero(station+1), d1 = (station == 0), d4 = (station == stationMax))
elif lcode[0] == 'red': # Red record button
toggleRec()
elif lcode[0] == 'menu': # Menu button opens top menu
topMenu()
elif lcode[0] == 'up' or lcode[0] == 'next': # Up/P+ buttons -- +1 station
nextSt()
elif lcode[0] == 'down' or lcode[0] == 'prev': # Down/P- buttons -- -1 station
prevSt()
elif lcode[0] == 'yellow': # Yellow button -- sleep menu
sleepMenu()
elif lcode[0] == 'green':
nowPlaying()
elif lcode[0] == 'blue':
fmRadio()
elif lcode[0] == 'rcl':
global isInVis
isInVis = not isInVis
elif lcode[0] == 'volup':
v = mix.getvolume()[0]
if v == 100L:
return
mix.setvolume(v+1)
v = mix.getvolume()[0]
v = str(v)
writeAll(
charToSeg(v[0]),
charToSeg(v[1]) if int(v) > 9 else 0x00,
charToSeg(v[2]) if int(v) > 99 else 0x00,
visFillBarW(math.floor(int(v)/50))
)
time.sleep(0.25)
elif lcode[0] == 'voldn':
v = mix.getvolume()[0]
if v == 0L:
return
mix.setvolume(v-1)
v = mix.getvolume()[0]
v = str(v)
writeAll(
charToSeg(v[0]),
charToSeg(v[1]) if int(v) > 9 else 0x00,
charToSeg(v[2]) if int(v) > 99 else 0x00,
visFillBarW(math.floor(int(v)/70))
)
time.sleep(0.25)
elif lcode[0] == 'help':
showWeather() # fuck all this romantic stuff, let's have functionality instead
# BEFORE: ? button shows an important counter value
#sd = datetime.datetime(2014, 9, 3, 0, 0, 0)
#now = datetime.datetime.now()
#delta = now - sd
#days = str(delta.days)+'d'
#transMessage(days)
#time.sleep(2)
#if clockOnPlayer:
# transClock()
#else:
# transMessage(intToStrLeadZero(station+1), d1 = (station == 0), d4 = (station == stationMax))
elif lcode[0].isdigit(): # Digit buttons
digits = 0
num = lcode[0]
a = ''
transMessage(num)
# Enter number input mode
while (a != 'ok' and a != 'menu' and digits != 3): # While we didn't press OK to confirm, Menu to cancel or didn't enter 4 digits
writeStr(num) # Display input
a = irCode() # Get next IR code
if a.isdigit(): # If code is digit
num = num + a # Write it in
digits = digits + 1
w.delay(5)
global station, cli, stationMax
if int(num) <= stationMax+1 and int(num) > 0 and a != 'menu': # Input number is valid, and we didn't press Menu to cancel
# Update the station no. and play it
station = int(num)-1
cli.play(station)
writeStr(intToStrLeadZero(station+1))
elif lcode[0] == u'pwron': # Power button on remote, this is needed
return True
else:
globalBreaker = (pwrBtn() or upBtn() or downBtn() or modeBtn())
if globalBreaker:
# debounce buttons
time.sleep(0.1)
return pwrBtn() or mustEnterAirport # this is needed too
writeStr("0000")
lastDispChangeDate = datetime.datetime.now()
lastDispTag = ''
globalBreaker = False
isInVis = False
about()
#Enable Airport
def APThreadCore():
processor = Processor()
processor.add_listener(AirportGoes) # function `event_processor` defined bellow.
processor.add_listener(AirportEvent) # function `event_processor` defined bellow.
processor.parse() # this will probably* run forever. (* If it doesn't crash, lol)
APThread = threading.Thread(group=None, target=APThreadCore)
APThread.daemon = True
APThread.start()
# ==================================== Now that's where it's at ================================
while True:
# try:
# We've just powered off or just booted
# Reset variables
now = datetime.datetime.now()
hrs = now.strftime("%H")
sleepEnabled = 0
sleepDur = 0
sleepBegan = 0
powerIsOn = 0
# Shut down audio
cli.stop()
cli.disconnect()
fmCastOff()
yel.setValue(0)
# Pretty fade the power LED
pwr.setValue(100)
time.sleep(1)
transClock()
if isRecing == 1:
grn.startBreathing()
else:
grn.setValue(0)
# While powered off
while not (powerOnCondition()):
clock() # Show clock
if mustEnterAirport:
airportMode()
if powerOnCondition():
break
time.sleep(0.5)
clickRelay(True)
now = datetime.datetime.now()
hrs = now.strftime("%H")
if int(hrs) < 12 and int(hrs) >= 6:
scrollMessage('good morning',delay=0.1, holdOff = 0, holdOn = 0, moveIn=True, fadeIn=True, moveOut = True)
elif int(hrs) >= 12 and int(hrs) < 18:
scrollMessage('hello',delay=0.1, holdOff = 0, holdOn = 0, moveIn=True, fadeIn=True, moveOut = True)
elif int(hrs) >= 18 and int(hrs) < 21:
scrollMessage('good evening ',delay=0.1, holdOff = 0, holdOn = 0, moveIn=True, fadeIn=True, moveOut = True)
else:
scrollMessage('hello ',delay=0.1, holdOff = 0, holdOn = 0, moveIn=True, fadeIn=True, moveOut = True)
cli.connect('localhost', 6600) # Set up media player
cli.single(1)
cli.repeat(1)
cli.consume(0)
# Pretty fade out
pwr.setValue(0)
grn.setValue(0)
# Update recording LED
if isRecing == 1: # Is recording
if recStation != station and grn.state != ST_BREATHE: # Recording NOT the station we're listening to
grn.startBreathing()
else: # Recording exactly what we're listening to
grn.setValue(100)
# Initialize audio
mix.setmute(0)
cli.play()
powerIsOn = 1
if clockOnPlayer:
transClock()
else:
transMessage(intToStrLeadZero(station+1), d1 = (station == 0), d4 = (station == stationMax))
# While irThread returns False (so no power button was hit)
lastDispChangeDate = datetime.datetime.now()
while not ( irThread() or radioBreaker ):
if not clockOnPlayer == 1: # Display mode is Station
delta = datetime.datetime.now() - lastDispChangeDate
csong = cli.currentsong()
try:
if 'title' in csong:
if (delta.seconds >= 60*10 or lastDispTag != csong['title']) and delta.seconds > 3:
snake(1)
lastDispTag = csong['title']
#if isFMCast:
# rdsFifo.write("RT "+str(lastDispTag))
if len(csong['title']) > 0:
scrollMessage(csong['title'], 0.1, True, 1, moveIn=True, fadeIn=False)
if not globalBreaker:
splashAnim(2)
lastDispChangeDate = datetime.datetime.now()
except:
pass
if not isInVis:
writeStr(intToStrLeadZero(station+1), d1 = (station == 0), d4 = (station == stationMax))
else:
visFrame()
globalBreaker = False
else: # Display mode is Clock while on
clock()
lastDispChangeDate = datetime.datetime.now()
if sleepEnabled == 1: # Sleep mode is on
sleepLen = (datetime.datetime.now() - sleepBegan).seconds / 60 # Check for how long it was
if sleepLen >= sleepDur: # If it's time to sleep,
break # skip to power off
if upBtn():
nextSt()
if downBtn():
prevSt()
if modeBtn():
topMenu()
time.sleep(0.1 if (not isInVis or clockOnPlayer == 1) else 0.01)
radioBreaker = False
if mustEnterAirport:
cli.stop()
airportMode()
if int(hrs) < 12 and int(hrs) >= 6:
scrollMessage('see you',delay=0.1, holdOff = 0, holdOn = 0, moveIn=True, fadeIn=True, moveOut = True)
elif int(hrs) >= 12 and int(hrs) < 18:
scrollMessage('bye-bye',delay=0.1, holdOff = 0, holdOn = 0, moveIn=True, fadeIn=True, moveOut = True)
elif int(hrs) >= 18 or int(hrs) < 6:
scrollMessage('good night',delay=0.1, holdOff = 0, holdOn = 0, moveIn=True, fadeIn=True, moveOut = True)
clickRelay(False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment