client: python3 conversion + small cleanup
[fuzzy_alarm_clock.git] / client / ur_fuzzy_alarm_clock.py
bloba202b3590658dacca7e8944c9e4a07dde90bbd05
1 #!/usr/bin/env python3
3 import datetime
4 import io
5 import logging
6 import sys
8 try:
9 import urwid
10 except ImportError:
11 logging.error('This program needs urwid')
12 sys.exit(1)
14 try:
15 import serial
16 except ImportError:
17 logging.error('This program needs pySerial')
18 sys.exit(1)
20 class FuzzyAlarmClock:
22 def __init__(self,device):
23 try:
24 self.serial = serial.Serial(device,9600,timeout=5)
25 except serial.serialutil.SerialException:
26 logging.warning('No such serial device {device}; mocking'.format(
27 device=device
29 self.serial = io.StringIO()
30 self.mock = True
31 else:
32 self.mock = False
34 def set_time_to_now(self):
35 now = 's'+datetime.datetime.now().strftime("%y%m%d%u%H%M%S")
36 self.serial.write(now)
38 def read_alarms(self,n):
39 data = []
40 self.serial.flushInput()
41 self.serial.write('p')
42 for i in range(n):
43 data.append(self.serial.readline())
44 for i in range(n):
45 data[i] = data[i].split(' ')[2:-1]
46 days = []
47 for j in range(8):
48 days.append(bool(int(data[i][0]) & 2**j))
49 days = days[7:8] + days[:7]
50 data[i] = days+data[i][1:]
51 return data
53 def set_alarm(self,alarm,values):
54 s = 'a'+str(alarm)
55 b0 = 0
56 for i,bit in enumerate(values[1:8] + values[0:1]):
57 b0 += bit << i
58 s += "%02x"%(b0)
59 for val in values[8:]:
60 s += "%02x"%(val)
61 self.serial.write(s)
63 class ModEdit(urwid.IntEdit):
65 def __init__(self,mod,caption="",default=None,offset=0):
66 self.mod = mod
67 self.offset = offset
69 super(ModEdit,self).__init__(caption,default)
71 def insert_text(self,text):
72 super(ModEdit,self).insert_text(text)
73 self.set_edit_text(str((self.value() - self.offset)% self.mod+self.offset))
76 class Alarm:
78 def __init__(self,aid,fac):
79 self.w_aid = urwid.Text(str(aid))
80 self.w_repeat = urwid.CheckBox("")
81 self.w_mon = urwid.CheckBox("")
82 self.w_tue = urwid.CheckBox("")
83 self.w_wed = urwid.CheckBox("")
84 self.w_thu = urwid.CheckBox("")
85 self.w_fri = urwid.CheckBox("")
86 self.w_sat = urwid.CheckBox("")
87 self.w_sun = urwid.CheckBox("")
88 self.w_month = ModEdit(12,offset=1)
89 self.w_day = ModEdit(31,offset=1)
90 self.w_hour = ModEdit(24,default=0)
91 self.w_minute = ModEdit(60,default=0)
93 self.widgets = urwid.Columns([self.w_aid,
94 self.w_repeat,
95 self.w_mon,
96 self.w_tue,
97 self.w_wed,
98 self.w_thu,
99 self.w_fri,
100 self.w_sat,
101 self.w_sun,
102 self.w_month,
103 self.w_day,
104 self.w_hour,
105 self.w_minute,
107 dividechars=1)
109 def set_values(self,values):
110 self.w_repeat.set_state(values[0])
111 self.w_mon.set_state(values[1])
112 self.w_tue.set_state(values[2])
113 self.w_wed.set_state(values[3])
114 self.w_thu.set_state(values[4])
115 self.w_fri.set_state(values[5])
116 self.w_sat.set_state(values[6])
117 self.w_sun.set_state(values[7])
118 self.w_month.set_edit_text(values[8])
119 self.w_day.set_edit_text(values[9])
120 self.w_hour.set_edit_text(values[10])
121 self.w_minute.set_edit_text(values[11])
123 def get_values(self):
124 return [
125 self.w_repeat.get_state(),
126 self.w_mon.get_state(),
127 self.w_tue.get_state(),
128 self.w_wed.get_state(),
129 self.w_thu.get_state(),
130 self.w_fri.get_state(),
131 self.w_sat.get_state(),
132 self.w_sun.get_state(),
133 self.w_month.value(),
134 self.w_day.value(),
135 self.w_hour.value(),
136 self.w_minute.value(),
140 class UI:
142 def __init__(self,fac):
143 self.fac = fac
145 self.alarm_number=4
147 self.frame = self.build_ui()
148 self.loop = urwid.MainLoop(self.frame,self.palette,unhandled_input=self.read_commands)
150 def build_ui(self):
151 self.palette = [
152 ('header', 'light gray', 'dark blue'),
153 ('footer', 'dark cyan', 'black')
156 self.alarms = []
157 for i in range(self.alarm_number):
158 self.alarms.append(Alarm(i,self.fac))
160 alarm_headers = urwid.Columns([
161 urwid.Text('#'),
162 urwid.Text('rep'),
163 urwid.Text('Mon'),
164 urwid.Text('Tue'),
165 urwid.Text('Wed'),
166 urwid.Text('Thu'),
167 urwid.Text('Fri'),
168 urwid.Text('Sat'),
169 urwid.Text('Sun'),
170 urwid.Text('mm'),
171 urwid.Text('dd'),
172 urwid.Text('HH'),
173 urwid.Text('MM'),
174 ],dividechars=1)
175 self.main_body = urwid.ListBox([alarm_headers]+[al.widgets for al in self.alarms])
177 footer = urwid.Text('a, b, c')
178 footer_map = urwid.AttrMap(footer,'footer')
180 header = urwid.Text('q: Quit r: Read s: Set n: time=Now ?:Help')
181 header_map = urwid.AttrMap(header,'header')
183 ui = urwid.Frame(self.main_body,footer=footer_map,header=header_map)
184 return ui
186 def read_commands(self,cmd):
187 {'n': self.fac.set_time_to_now,
188 'r': self.read_alarms,
189 's': self.set_alarms,
190 '?': self.print_help,
191 'q': self.quit
192 }.get(cmd,self.do_nothing)()
194 def do_nothing(self):
195 pass
197 def read_alarms(self):
198 alarms = self.fac.read_alarms(self.alarm_number)
200 for i, al in enumerate(alarms):
201 self.alarms[i].set_values(al)
203 def set_alarms(self):
204 for i,alarm in enumerate(self.alarms):
205 self.fac.set_alarm(i,alarm.get_values())
207 def print_help(self):
208 pass
210 def quit(self):
211 raise urwid.ExitMainLoop()
213 def run(self):
214 self.loop.run()
217 def main():
218 fac = FuzzyAlarmClock('/dev/ttyUSB0')
219 ui = UI(fac)
220 ui.run()
222 if __name__ == '__main__': main()