· 8 years ago · Mar 02, 2018, 02:15 PM
1# -*- coding: UTF-8 -*-
2
3"""Reads input from GPIO with a reduced number of pins."""
4
5import time
6import RPi.GPIO as GPIO
7from configparser import ConfigParser
8
9class Matrix():
10
11 def __init__(self):
12 """Sets up constants and pin numbers."""
13 # BCM (Broadcom) numbers are used
14 GPIO.setmode(GPIO.BCM)
15 parser = ConfigParser()
16 filename = 'config.ini'
17 parser.read(filename)
18 gpio = parser['gpio']
19 selection = parser['selection']
20 self.rows = list(map(int, gpio['button_rows'].split(',')))
21 self.columns = list(map(int, gpio['button_columns'].split(',')))
22 topics = selection['topics'].replace(" ","").split(',')
23 actions = selection['actions'].replace(" ","").split(',')
24 while len(actions) <= len(topics):
25 actions.append('unassigned')
26 self.options_array = [
27 topics,
28 actions
29 ]
30
31 def get_button(self):
32 """Findet gedrueckte Knoepfe und returnt Koordinaten falls gefunden."""
33
34 # To search for the row of a pressed button:
35 # - set all rows to input
36 # - set all columns to output low
37 # - save index in row_position
38
39 row_position = -1
40
41 for i in range(len(self.columns)):
42 GPIO.setup(self.columns[i], GPIO.OUT)
43 GPIO.output(self.columns[i], GPIO.LOW)
44
45 for i in range(len(self.rows)):
46 GPIO.setup(self.rows[i], GPIO.IN, pull_up_down=GPIO.PUD_UP)
47
48 for i in range(len(self.rows)):
49 temp_read = GPIO.input(self.rows[i])
50 if temp_read == 0:
51 row_position = i
52
53 # cancel if no input was found
54 if row_position < 0 or row_position >= len(self.rows):
55 self.refresh()
56 return
57
58 # To search for the column of a pressed button in the row:
59 # - set all columns to input
60 # - rows[row_position] to output
61
62 column_position = -1
63
64 for j in range(len(self.columns)):
65 GPIO.setup(self.columns[j], GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
66
67 GPIO.setup(self.rows[row_position], GPIO.OUT)
68 GPIO.output(self.rows[row_position], GPIO.HIGH)
69
70 for j in range(len(self.columns)):
71 temp_read = GPIO.input(self.columns[j])
72 if temp_read == 1:
73 column_position = j
74
75 # cancel if no input was found
76 if column_position < 0 or column_position >= len(self.columns):
77 self.refresh()
78 return
79
80 # returns coordinates of pressed button
81 self.refresh()
82 return self.options_array[row_position][column_position]
83
84 def refresh(self):
85 """Resets all pin states."""
86 for i in range(len(self.rows)):
87 GPIO.setup(self.rows[i], GPIO.IN, pull_up_down=GPIO.PUD_UP)
88 for j in range(len(self.columns)):
89 GPIO.setup(self.columns[j], GPIO.IN, pull_up_down=GPIO.PUD_UP)
90
91if __name__ == '__main__':
92 # For testing matrix functionality
93 while True:
94 user_input = None
95 while user_input is None:
96 user_input = Matrix().get_button()
97 print(user_input)
98 time.sleep(.2)
99
100#!/usr/bin/python3
101
102"""Waits for input from matrix.py and hands over selection to database_commit.py on confirmation."""
103
104import time
105import signal
106import sys
107import threading
108import RPi.GPIO as GPIO
109from threading import Timer
110from configparser import ConfigParser
111from matrix import Matrix
112from database_commit import DatabaseCommit as database
113
114class Controller():
115 """Waits for input from matrix.py and hands over selection to database_commit.py on confirmation."""
116 def __init__(self):
117 """Sets up constants."""
118 # Use Broadcom-Numbering
119 GPIO.setmode(GPIO.BCM)
120
121 # Get constants from config.ini
122 parser = ConfigParser()
123 filename = 'config.ini'
124 parser.read(filename)
125
126 # Pin adresses
127 gpio = parser['gpio']
128
129 self.TOPICS_LED = list(map(int, gpio['topics_led'].split(',')))
130 self.ACTIONS_LED = list(map(int, gpio['actions_led'].split(',')))
131 self.CANCEL_LED = self.ACTIONS_LED[0]
132 self.CONFIRM_LED = self.ACTIONS_LED[1]
133 self.POST_LED = self.ACTIONS_LED[2]
134 self.NAGIOS_LED = self.ACTIONS_LED[3]
135
136 # names, defaults, timers
137 selection = parser['selection']
138
139 self.TOPICS = selection['topics'].replace(" ", "").split(',')
140 self.ACTIONS = selection['actions'].replace(" ", "").split(',')
141 self.CANCEL = self.ACTIONS[0]
142 self.CONFIRM = self.ACTIONS[1]
143 self.POST = self.ACTIONS[2]
144 self.NAGIOS = self.ACTIONS[3]
145 self.DEFAULT_SELECTION = selection['default_selection'].replace(" ", "").split(',')
146 self.DEFAULT_LED_STATE = [False] * len(self.TOPICS_LED)
147 self.SLEEP = float(selection['sleeptime'])
148 self.BLINK = float(selection['blinktime'])
149 self.SEND_DEFAULT_ON_EMPTY = bool(selection['send_default_on_empty'])
150
151 # reminder schedule
152 schedule = parser['schedule']
153
154 self.POST_TIME = time.strptime(schedule['post'].replace(":", " "), '%H %M')
155 self.NAGIOS_TIME = time.strptime(schedule['nagios'].replace(":", " "), '%H %M')
156
157 self.current_selection = self.DEFAULT_SELECTION[:]
158 self.led_state = self.DEFAULT_LED_STATE[:]
159
160 # Setup the LED pins
161 for i in range(len(self.TOPICS_LED)):
162 GPIO.setup(self.TOPICS_LED[i], GPIO.OUT)
163 GPIO.output(self.TOPICS_LED[i], GPIO.LOW)
164 for i in range(len(self.ACTIONS_LED)):
165 GPIO.setup(self.ACTIONS_LED[i], GPIO.OUT)
166 GPIO.output(self.ACTIONS_LED[i], GPIO.LOW)
167
168 # Switch on default selection LEDs
169 for i in range(len(self.DEFAULT_SELECTION)):
170 for j in range(len(self.TOPICS)):
171 if self.DEFAULT_SELECTION[i] == self.TOPICS[j]:
172 GPIO.output(self.TOPICS_LED[j], GPIO.HIGH)
173 self.led_state[j] = True
174
175 # Notification status
176 self.post_notification = False
177 self.nagios_notification = False
178
179
180
181 def led_reset_topics(self):
182 """Disable all LEDs and enable default selection LEDs"""
183 # All off
184 for i in range(len(self.TOPICS_LED)):
185 GPIO.output(self.TOPICS_LED[i], GPIO.LOW)
186 # Default an
187 for i in range(len(self.DEFAULT_SELECTION)):
188 for j in range(len(self.TOPICS)):
189 if self.DEFAULT_SELECTION[i] == self.TOPICS[j]:
190 GPIO.output(self.TOPICS_LED[j], GPIO.HIGH)
191 self.led_state[j] = True
192 return
193
194 def continous_led_blink(blink_event, blink_thread, led):
195 """Blink action LED continuously"""
196 while not blink_event.isSet():
197 GPIO.output(led, GPIO.HIGH)
198 time.sleep(self.BLINK)
199 event_is_set = blink_event.wait(blink_thread)
200 if event_is_set:
201 GPIO.output(led, GPIO.LOW)
202 else:
203 GPIO.output(led, GPIO.LOW)
204 time.sleep(self.BLINK)
205
206 def led_blink(self, led_pin):
207 """Blink action LED
208 """
209 t = Timer(self.BLINK, GPIO.output, [led_pin, GPIO.LOW])
210 GPIO.output(led_pin, GPIO.HIGH)
211 #time.sleep(.2)
212 #GPIO.output(led_pin, GPIO.LOW)
213 t.start()
214 return
215
216 def dismiss_notification(self, led_pin):
217 """Disables notification LED
218 :param led_pin: GPIO pin number
219 """
220 GPIO.output(led_pin, GPIO.LOW)
221
222
223 def led_toggle_topic(self, led_index):
224 """Toggles LED state of led_index
225 :param led_index: Index in TOPICS_LED; contains GPIO pin number"""
226 self.led_state[led_index] = not self.led_state[led_index]
227 if self.led_state[led_index]:
228 GPIO.output(self.TOPICS_LED[led_index], GPIO.HIGH)
229 else:
230 GPIO.output(self.TOPICS_LED[led_index], GPIO.LOW)
231 return
232
233 def handle_selection(self, user_input):
234 """
235 Handles de/selection of topics
236 Returns False if selection is altered
237 Returns True if CANCEL or COMMIT is chosen
238 :param user_input: String, name of pressed button
239 """
240
241 # If cancelled, reset to default selection
242 if user_input == self.CANCEL:
243 self.led_blink(self.CANCEL_LED)
244 self.current_selection = self.DEFAULT_SELECTION[:]
245 self.led_reset_topics()
246 return True
247
248 # If selection is non-empty, commit selection
249 # - selection array is always sorted
250 # If selection is empty, reset to default selection
251 # and send default selection if SEND_DEFAULT_ON_EMPTY is True
252 elif user_input == self.CONFIRM:
253 self.led_blink(self.CONFIRM_LED)
254 if self.current_selection != []:
255 #self.current_selection.sort()
256 database().make_commit(self.current_selection)
257 self.current_selection = self.DEFAULT_SELECTION[:]
258 else:
259 self.current_selection = self.DEFAULT_SELECTION[:]
260 if self.SEND_DEFAULT_ON_EMPTY:
261 if len(self.DEFAULT_SELECTION) > 0:
262 database().make_commit(self.current_selection)
263 return True
264
265 # TODO
266 # Disable "Post" notification
267 elif user_input == self.POST:
268 """self.post_notification = False
269 self.blink_thread.start()
270 self.dismiss_notification(self.POST_LED)
271 return False"""
272
273 # TODO
274 # Disable "Nagios" notification
275 elif user_input == self.NAGIOS:
276 """self.nagios_notification = False
277 self.dismiss_notification(self.NAGIOS_LED)
278 return False"""
279
280 else:
281 # Compare input with all TOPICS
282 for i in range(len(self.TOPICS)):
283 if user_input == self.TOPICS[i]:
284 self.led_toggle_topic(i)
285 already_exists = False
286 # Delete if exists already
287 for j in range(len(self.current_selection)):
288 if user_input == self.current_selection[j]:
289 already_exists = True
290 self.current_selection.pop(j)
291 print(user_input + " -")
292 break
293 # Add if does not exits yet
294 if not already_exists:
295 self.current_selection.append(user_input)
296 print(user_input + " +")
297 # Sort array
298 # Same order as in TOPICS
299 self.temp_selection = []
300 for l in range(len(self.TOPICS)):
301 self.temp_selection.append("")
302 for i in range(len(self.TOPICS)):
303 for j in range(len(self.current_selection)):
304 if self.TOPICS[i] == self.current_selection[j]:
305 self.temp_selection[i]=self.TOPICS[i]
306 self.temp_selection = list(filter(None, self.temp_selection))
307 self.current_selection = self.temp_selection[:]
308 return False
309
310 def wait_for_input(self):
311 """Wartet auf Input und gibt an handle_selection weiter."""
312
313 done_with_input = False
314 while not done_with_input:
315 user_input = None
316 while user_input is None:
317 user_input = Matrix().get_button()
318 done_with_input = self.handle_selection(user_input)
319 time.sleep(self.SLEEP)
320 return
321
322if __name__ == '__main__':
323 GPIO.setwarnings(False)
324 database().external_prepare_table()
325 while True:
326 Controller().wait_for_input()
327 GPIO.cleanup()
328 sys.exit(0)
329
330#!/usr/bin/python
331# -*- coding: UTF-8 -*-
332
333import datetime
334import time
335from configparser import ConfigParser
336from mysql.connector import MySQLConnection, Error
337
338class DatabaseCommit():
339
340 def read_config(section, filename='config.ini'):
341 """ Reads config.ini and returns dictionary with config from section
342 :param filename: name of config file
343 :param section: name of section in config file
344 :return: dictionary with database settings
345 """
346
347 parser = ConfigParser()
348 parser.read(filename)
349 config = {}
350 if parser.has_section(section):
351 items = parser.items(section)
352 for item in items:
353 config[item[0]] = item[1].replace(" ", "")
354 else:
355 raise Exception('{0} not found in {1} '.format(section, filename))
356
357 return config
358
359 def establish_connection(self):
360 db_config = DatabaseCommit.read_config('mysql')
361 conn = MySQLConnection(**db_config)
362 if conn.is_connected():
363 return conn
364 else:
365 print("Connection failed")
366
367 def prepare_table(self, cursor):
368 # TODO check for existing tables, add any if neccessary, fill with 0
369 database_name = DatabaseCommit.read_config('mysql')['database'].replace(" ", "")
370 table_name = DatabaseCommit.read_config('table')['table_name'].replace(" ", "")
371 counter_column = DatabaseCommit.read_config('table')['counter_column'].replace(" ", "")
372 date_column = DatabaseCommit.read_config('table')['date_column'].replace(" ", "")
373 sql = 'CREATE TABLE IF NOT EXISTS '+ table_name +' ('
374 sql += counter_column +' INT PRIMARY KEY AUTO_INCREMENT, '
375 sql += date_column +' DATETIME'
376 for topic in DatabaseCommit.read_config('selection')['topics'].replace(" ", "").split(','):
377 topic = topic.lower()
378 sql += ', '+ topic +' BOOLEAN NOT NULL DEFAULT 0'
379 sql += ');'
380 print("n"+sql+"n")
381 cursor.execute(sql)
382 sql = ''
383 return cursor
384
385 def external_prepare_table(self):
386 conn = self.establish_connection()
387 cursor = conn.cursor()
388 self.prepare_table(cursor)
389
390 def insert_user_input(self, user_input, cursor, table_name):
391 date_column = DatabaseCommit.read_config('table')['date_column']
392 sql = 'INSERT INTO ' + table_name + '(' + date_column
393 for topic in user_input:
394 sql += ','+ topic
395 sql += ')'
396 sql += 'VALUES(NOW()'
397 for topic in user_input:
398 sql += ','+'TRUE'
399 sql += ')'
400 cursor.execute(sql)
401
402 def make_commit(self, user_input):
403 conn = self.establish_connection()
404 cursor = conn.cursor()
405 #self.prepare_table(cursor)
406 table_name = DatabaseCommit.read_config('table')['table_name']
407 self.insert_user_input(user_input, cursor, table_name)
408 cursor.execute('COMMIT;')
409 print("made commit :")
410 print(user_input)
411 cursor.close()
412 conn.close()
413
414[gpio]
415button_rows = 4, 17
416button_columns = 18, 23, 24, 25, 12, 16
417topics_led = 2, 3, 27, 22, 10, 9
418actions_led = 11, 5, 6, 13, 19, 26
419
420[selection]
421topics = topic_1, topic_2, topic_3, topic_4, topic_5, topic_6
422actions = Cancel, Commit, Post, Rundgang, unassigned_1, unassigned_2
423default_selection = topic_2
424sleeptime = .3
425blinktime = .2
426send_default_on_empty = True
427
428[schedule]
429post = 11:30
430nagios = 09:30
431
432[mysql]
433host = 127.0.0.1
434database = mydatabase
435user = rpi
436password = password
437
438[table]
439table_name = test
440counter_column = number
441date_column = date