from microdot import Microdot, send_file import machine, sys, neopixel, time app = Microdot() # Difine NeoPixel object nbPixels = 12*2 pinPixelStrip = 16 # ESP32 D1 Mini neoPixelStrip = neopixel.NeoPixel(machine.Pin(pinPixelStrip), nbPixels) # Define status colors statusColors = { 'BUSY': (255,0,0), # red 'AVAILABLE': (0,255,0), # green 'AWAY': (246,190,0), # cyan 'OFF': (0, 0, 0), # off 'ON': (255, 255, 255) # white } # Store BusyLight default global status blColor = statusColors.get('OFF') blStatus = 'off' blPreviousStatus='off' blBrightness = 0.1 # Adjust the brightness (0.0 - 1.0) def __setColor(color): r, g , b = color r = int(r * blBrightness) g = int(g * blBrightness) b = int(b * blBrightness) return (r, g, b) def __setBusyLightColor(color, brightness): global blBrightness blBrightness = brightness global blColor blColor = color neoPixelStrip.fill(__setColor(color)) neoPixelStrip.write() global blStatus blStatus = 'colored' def __setBusyLightStatus(status): status = status.upper() color = statusColors.get(status) __setBusyLightColor(color, blBrightness) global blStatus blStatus = status.lower() # Microdot APP routes @app.get('/static/') async def staticRoutes(request, path): if '..' in path: # directory traversal is not allowed return {'error': '4040 Not found'}, 404 return send_file('static/' + path) @app.get('/') async def getIndex(request): return send_file('static/index.html') @app.get('/api/brightness') async def getBrightness(request): return {'brightness': blBrightness} @app.post('/api/brightness') async def setBrightness(request): brightness = request.json.get("brightness") if brightness is None: return {'error': 'missing brightness parameter'}, 400 if type(brightness) is float \ or type(brightness) is int: if brightness < 0 or brightness > 1: return {'error': 'brigthness out of bound (0.0 - 1.0)'}, 400 else: return {'error': 'wrong brigthness type (float)'}, 400 # Save blStatus global blStatus status = blStatus # Apply new brightness to current color color = blColor __setBusyLightColor(color, brightness) # Restore global status blStatus = status global blBrightness blBrightness = brightness return {'brightness': blBrightness} @app.post('/api/color') async def setColor(request): r = request.json.get("r") g = request.json.get("g") b = request.json.get("b") if bool(r is None or g is None or b is None): return {'error': 'missing color'}, 400 else: if type(r) is int \ and type(g) is int \ and type(b) is int: color = (r, g, b) else: return {'error': 'wrong color type (int)'}, 400 if (r < 0 or r > 255) \ or (g < 0 or g > 255) \ or (b < 0 or b > 255): return {'error': 'color out of bound (0 - 255)'}, 400 brightness = request.json.get("brightness") if not brightness is None: if type(brightness) is float \ or type(brightness) is int: if brightness < 0 or brightness > 1: return {'error': 'brightness out of bound (0.0 - 1.0)'}, 400 else: return {'error': 'wrong brightness type (float)'}, 400 __setBusyLightColor(color, brightness) __setBusyLightColor(color, blBrightness) return {'status': blStatus} @app.route('/api/status/', methods=['GET', 'POST']) async def setStatus(request, status): lStatus = status.lower() if lStatus == 'on': __setBusyLightStatus('ON') elif lStatus == 'off': __setBusyLightStatus('OFF') elif lStatus == 'available': __setBusyLightStatus('AVAILABLE') elif lStatus == 'away': __setBusyLightStatus('AWAY') elif lStatus == 'busy': __setBusyLightStatus('BUSY') else: return {'error': 'unknown /api/status/' + lStatus + ' route'}, 404 return {'status': blStatus} @app.get('/api/color') async def getColor(request): r, g, b = neoPixelStrip.__getitem__(0) return {'color': {'r': r, 'g': g, 'b': b}} @app.get('/api/status') async def getStatus(request): return {'status': blStatus} @app.get('/api/debug') async def getDebugInfo(request): r, g, b = blColor dr, dg, db = neoPixelStrip.__getitem__(0) return {'status': blStatus, 'brightness': blBrightness, 'color': {'r': r, 'g': g, 'b': b}, 'dimColor': {'r': dr, 'g': dg, 'b': db}} @app.post('/api/mutedeck-webhook') async def mutedeckWebhook(request): if request.json.get('control') != 'system': if request.json.get('call') == 'active': if request.json.get('mute') == 'active': isMuted = True else: isMuted = False if request.json.get('video') == 'active': isVideoOn = True else: isVideoOn = False if isMuted: __setBusyLightStatus('away') else: __setBusyLightStatus('busy') else: __setBusyLightStatus('available') return {'status': blStatus} @app.post('/shutdown') async def shutdown(request): request.app.shutdown() return 'The server is shutting down...' # Startup effect def startUpSeq(): print('Start seq begins') __setBusyLightStatus('OFF') time.sleep_ms(100) __setBusyLightStatus('BUSY') time.sleep_ms(200) __setBusyLightStatus('AWAY') time.sleep_ms(300) __setBusyLightStatus('AVAILABLE') time.sleep_ms(500) __setBusyLightStatus('OFF') print('Start seq is ended') __setBusyLightColor(statusColors.get('OFF'), 0.4) startUpSeq() # Start API webserver if __name__ == '__main__': app.run(port=80, debug=True)