kegomatic.py
1 # SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 #!/usr/bin/python 6 import os 7 import time 8 import math 9 import logging 10 import pygame, sys 11 from pygame.locals import * 12 import RPi.GPIO as GPIO 13 from twitter import * 14 from flowmeter import * 15 from adabot import * 16 from seekrits import * 17 18 t = Twitter( auth=OAuth(OAUTH_TOKEN, OAUTH_SECRET, CONSUMER_KEY, CONSUMER_SECRET) ) 19 #boardRevision = GPIO.RPI_REVISION 20 GPIO.setmode(GPIO.BCM) # use real GPIO numbering 21 GPIO.setup(23,GPIO.IN, pull_up_down=GPIO.PUD_UP) 22 GPIO.setup(24,GPIO.IN, pull_up_down=GPIO.PUD_UP) 23 24 # set up pygame 25 pygame.init() 26 27 # set up the window 28 VIEW_WIDTH = 1024 29 VIEW_HEIGHT = 576 30 pygame.display.set_caption('KEGBOT') 31 lastTweet = 0 32 view_mode = 'normal' 33 34 # hide the mouse 35 pygame.mouse.set_visible(False) 36 37 # set up the flow meters 38 fm = FlowMeter('metric', ["beer"]) 39 fm2 = FlowMeter('metric', ["root beer"]) 40 tweet = '' 41 # set up the colors 42 BLACK = (0,0,0) 43 WHITE = (255,255,255) 44 45 # set up the window surface 46 windowSurface = pygame.display.set_mode((VIEW_WIDTH,VIEW_HEIGHT), FULLSCREEN, 32) 47 windowInfo = pygame.display.Info() 48 FONTSIZE = 48 49 LINEHEIGHT = 28 50 basicFont = pygame.font.SysFont(None, FONTSIZE) 51 52 # set up the backgrounds 53 bg = pygame.image.load('beer-bg.png') 54 tweet_bg = pygame.image.load('tweet-bg.png') 55 56 # set up the adabots 57 back_bot = adabot(361, 151, 361, 725) 58 middle_bot = adabot(310, 339, 310, 825) 59 front_bot = adabot(220, 527, 220, 888) 60 61 # draw some text into an area of a surface 62 # automatically wraps words 63 # returns any text that didn't get blitted 64 def drawText(surface, text, color, rect, font, aa=False, bkg=None): 65 rect = Rect(rect) 66 y = rect.top 67 lineSpacing = -2 68 69 # get the height of the font 70 fontHeight = font.size("Tg")[1] 71 72 while text: 73 i = 1 74 75 # determine if the row of text will be outside our area 76 if y + fontHeight > rect.bottom: 77 break 78 79 # determine maximum width of line 80 while font.size(text[:i])[0] < rect.width and i < len(text): 81 i += 1 82 83 # if we've wrapped the text, then adjust the wrap to the last word 84 if i < len(text): 85 i = text.rfind(" ", 0, i) + 1 86 87 # render the line and blit it to the surface 88 if bkg: 89 image = font.render(text[:i], 1, color, bkg) 90 image.set_colorkey(bkg) 91 else: 92 image = font.render(text[:i], aa, color) 93 94 surface.blit(image, (rect.left, y)) 95 y += fontHeight + lineSpacing 96 97 # remove the text we just blitted 98 text = text[i:] 99 100 return text 101 102 def renderThings(flowMeter, flowMeter2, tweet, windowSurface, basicFont): 103 # Clear the screen 104 windowSurface.blit(bg,(0,0)) 105 106 # draw the adabots 107 back_bot.update() 108 windowSurface.blit(back_bot.image,(back_bot.x, back_bot.y)) 109 middle_bot.update() 110 windowSurface.blit(middle_bot.image,(middle_bot.x, middle_bot.y)) 111 front_bot.update() 112 windowSurface.blit(front_bot.image,(front_bot.x, front_bot.y)) 113 114 # Draw Ammt Poured 115 text = basicFont.render("CURRENT", True, WHITE, BLACK) 116 textRect = text.get_rect() 117 windowSurface.blit(text, (40,20)) 118 if fm.enabled: 119 text = basicFont.render(fm.getFormattedThisPour(), True, WHITE, BLACK) 120 textRect = text.get_rect() 121 windowSurface.blit(text, (40,30+LINEHEIGHT)) 122 if fm2.enabled: 123 text = basicFont.render(fm2.getFormattedThisPour(), True, WHITE, BLACK) 124 textRect = text.get_rect() 125 windowSurface.blit(text, (40, 30+(2*(LINEHEIGHT+5)))) 126 127 # Draw Ammt Poured Total 128 text = basicFont.render("TOTAL", True, WHITE, BLACK) 129 textRect = text.get_rect() 130 windowSurface.blit(text, (windowInfo.current_w - textRect.width - 40, 20)) 131 if fm.enabled: 132 text = basicFont.render(fm.getFormattedTotalPour(), True, WHITE, BLACK) 133 textRect = text.get_rect() 134 windowSurface.blit(text, (windowInfo.current_w - textRect.width - 40, 30 + LINEHEIGHT)) 135 if fm2.enabled: 136 text = basicFont.render(fm2.getFormattedTotalPour(), True, WHITE, BLACK) 137 textRect = text.get_rect() 138 windowSurface.blit(text, (windowInfo.current_w - textRect.width - 40, 30 + (2 * (LINEHEIGHT+5)))) 139 140 if view_mode == 'tweet': 141 windowSurface.blit(tweet_bg,(0,0)) 142 textRect = Rect(545,265,500,225) 143 drawText(windowSurface, tweet, BLACK, textRect, basicFont, True, None) 144 145 # Display everything 146 pygame.display.flip() 147 148 # Beer, on Pin 23. 149 def doAClick(channel): 150 currentTime = int(time.time() * FlowMeter.MS_IN_A_SECOND) 151 if fm.enabled == True: 152 fm.update(currentTime) 153 154 # Root Beer, on Pin 24. 155 def doAClick2(channel): 156 currentTime = int(time.time() * FlowMeter.MS_IN_A_SECOND) 157 if fm2.enabled == True: 158 fm2.update(currentTime) 159 160 def tweetPour(theTweet): 161 try: 162 t.statuses.update(status=theTweet) 163 except: 164 logging.warning('Error tweeting: ' + theTweet + "\n") 165 166 GPIO.add_event_detect(23, GPIO.RISING, callback=doAClick, bouncetime=20) # Beer, on Pin 23 167 GPIO.add_event_detect(24, GPIO.RISING, callback=doAClick2, bouncetime=20) # Root Beer, on Pin 24 168 169 # main loop 170 while True: 171 # Handle keyboard events 172 for event in pygame.event.get(): 173 if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE): 174 GPIO.cleanup() 175 pygame.quit() 176 sys.exit() 177 elif event.type == KEYUP and event.key == K_1: 178 fm.enabled = not(fm.enabled) 179 elif event.type == KEYUP and event.key == K_2: 180 fm2.enabled = not(fm2.enabled) 181 elif event.type == KEYUP and event.key == K_9: 182 fm.clear() 183 elif event.type == KEYUP and event.key == K_0: 184 fm2.clear() 185 186 currentTime = int(time.time() * FlowMeter.MS_IN_A_SECOND) 187 188 if currentTime - lastTweet < 5000: # Pause for 5 seconds after tweeting to show the tweet 189 view_mode = 'tweet' 190 else: 191 view_mode = 'normal' 192 193 if (fm.thisPour > 0.23 and currentTime - fm.lastClick > 10000): # 10 seconds of inactivity causes a tweet 194 tweet = "Someone just poured " + fm.getFormattedThisPour() + " of " + fm.getBeverage() + " from the Adafruit kegomatic!" 195 lastTweet = int(time.time() * FlowMeter.MS_IN_A_SECOND) 196 fm.thisPour = 0.0 197 tweetPour(tweet) 198 199 if (fm2.thisPour > 0.23 and currentTime - fm2.lastClick > 10000): # 10 seconds of inactivity causes a tweet 200 tweet = "Someone just poured " + fm2.getFormattedThisPour() + " of " + fm2.getBeverage() + " from the Adafruit kegomatic!" 201 lastTweet = int(time.time() * FlowMeter.MS_IN_A_SECOND) 202 fm2.thisPour = 0.0 203 tweetPour(tweet) 204 205 # reset flow meter after each pour (2 secs of inactivity) 206 if (fm.thisPour <= 0.23 and currentTime - fm.lastClick > 2000): 207 fm.thisPour = 0.0 208 209 if (fm2.thisPour <= 0.23 and currentTime - fm2.lastClick > 2000): 210 fm2.thisPour = 0.0 211 212 # Update the screen 213 renderThings(fm, fm2, tweet, windowSurface, basicFont)