/ Kegomatic / kegomatic.py
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)