Ejemplo n.º 1
0
    def __init__(self):
        self.endCheckValue = -1
        self.widthScaleParam = 1 
        #Lチカ
        #self.ledRed = machine.PWM(21)
        #self.ledGreen = machine.PWM(22)
        #self.ledBlue = machine.PWM(3)
        #self.ledRed.freq(440)
        #self.ledGreen.freq(440)
        #self.ledBlue.freq(440)

        #Neopixel
        led_pin = 15
        self.led_num = 10
        self.leds = Neopixel(led_pin, self.led_num)
Ejemplo n.º 2
0
 def init(self):
     """ Init logic; connect to wifi, connect to MQTT and setup RTC/NTP """
     self._log('Connecting to wifi ({0})... '.format(self._wifi_credentials[0]), tft=True)
     self._wlan = network.WLAN(network.STA_IF)
     self._wlan.active(True)
     self._wlan.connect(*self._wifi_credentials)
     safety = 10
     while not self._wlan.isconnected() and safety > 0:
         # Wait for the wifi to connect, max 10s
         time.sleep(1)
         safety -= 1
     self._log('Connecting to wifi ({0})... {1}'.format(self._wifi_credentials[0], 'Done' if safety else 'Fail'))
     mac_address = ubinascii.hexlify(self._wlan.config('mac'), ':').decode()
     self._log('Connecting to MQTT...', tft=True)
     if self._mqtt is not None:
         self._mqtt.unsubscribe('emon/#')
     self._mqtt = network.mqtt('emon', self._mqtt_broker, user='******', password='******', clientid=mac_address, data_cb=self._process_data)
     self._mqtt.start()
     safety = 5
     while self._mqtt.status()[0] != 2 and safety > 0:
         # Wait for MQTT connection, max 5s
         time.sleep(1)
         safety -= 1
     self._mqtt.subscribe('emon/#')
     self._log('Connecting to MQTT... {0}'.format('Done' if safety else 'Fail'))
     self._log('Sync NTP...', tft=True)
     self._rtc.ntp_sync(server='be.pool.ntp.org', tz='CET-1CEST-2')
     safety = 5
     while not self._rtc.synced() and safety > 0:
         # Wait for NTP time sync, max 5s
         time.sleep(1)
         safety -= 1
     self._last_update = self._rtc.now()
     self._log('Sync NTP... {0}'.format('Done' if safety else 'Fail'))
     self._log('Initializing Neopixels...', tft=True)
     try:
         self._neopixel = Neopixel(Pin(15), 10, Neopixel.TYPE_RGB)
         self._neopixel.clear()
     except Exception:
         self._neopixel = None
     self._log('Initializing Neopixels... {0}'.format('Available' if self._neopixel is not None else 'Unavailable'))
     self._tft.text(0, 14, ' ' * 50, self._tft.DARKGREY)  # Clear the line
Ejemplo n.º 3
0
class RGB():  # 0 IN 1 OUT
    def __init__(self, port=PORTB, nums=1):
        from machine import Neopixel
        self.nums = nums * 3
        self.np = Neopixel(Pin(port[0]), self.nums)
        # self.np = Neopixel(Pin(port[0]), self.nums, Neopixel.TYPE_RGBW)

    def setColor(self, color, pos=None):
        if pos == None:
            self.np.set(1, color, num=self.nums)
        else:
            self.np.set(pos, color)

    def setHSB(self, hue, saturation, brightness, pos=None):
        if pos == None:
            self.np.setHSB(1, hue, saturation, brightness, num=self.nums)
        else:
            self.np.setHSB(pos, hue, saturation, brightness)

    def deinit(self):
        self.np.deinit()
Ejemplo n.º 4
0
 def __init__(self, port=PORTB, nums=1):
     from machine import Neopixel
     self.nums = nums * 3
     self.np = Neopixel(Pin(port[0]), self.nums)
Ejemplo n.º 5
0
class RetroPCCG:
    
    PAINT_BUFFER = 250
    DATA_END = -999

    def __init__(self):
        self.endCheckValue = -1
        self.widthScaleParam = 1 
        #Lチカ
        #self.ledRed = machine.PWM(21)
        #self.ledGreen = machine.PWM(22)
        #self.ledBlue = machine.PWM(3)
        #self.ledRed.freq(440)
        #self.ledGreen.freq(440)
        #self.ledBlue.freq(440)

        #Neopixel
        led_pin = 15
        self.led_num = 10
        self.leds = Neopixel(led_pin, self.led_num)

    def setParam(self, widthScale, endCheck):
        self.widthScaleParam = widthScale
        self.endCheckValue =  endCheck

    def executePaint(self, fileName):
        print(fileName)
        #PaintBuffer
        self.screenBuffer = barray.BARRAY(76800)
        self.dataFile = open(fileName, "r") 
        self.currentFileLine = ""

        sizeX = self.readData() #データの横ピクセル数
        sizeY = self.readData() #データの縦ピクセル数
        
        rateX = 320 / sizeX  
        rateY = 240 / sizeY 
        
        #入りきる側の倍率に合わせる
        if rateX < rateY:
            rateY = rateX / self.widthScaleParam
        else:
            rateX = rateY
        
        bgColor = self.readData()
        frameColor = self.readData()

        #X, Y, backGroundColor,FrameColor
        lcd.clear(bgColor)
        
        self.offsetX = int((320 - sizeX * rateX) / 2)
        self.offsetY = int((240 - sizeY * rateY) / 2)
        
        #画面サイズより小さい場合、枠を描く
        if self.offsetX > 0:
            self.drawLine(self.offsetX, 0 + self.offsetY , self.offsetX,sizeY + self.offsetY, frameColor)
            self.drawLine(sizeX + self.offsetX, 0 + self.offsetY, sizeX + self.offsetX , sizeY + self.offsetY, frameColor)
        
        if self.offsetY > 0:
            self.drawLine(0 + self.offsetX, self.offsetY, sizeX + self.offsetX, self.offsetY, frameColor)
            self.drawLine(0 + self.offsetX, sizeY + self.offsetY, sizeX + self.offsetX , sizeY + self.offsetY , frameColor)
        
        startX = 0
        endX = 0
        startY = 0
        endY = 0  
        color = 0
        
        fileEnd = False
        status = Status.NONE
        while fileEnd == False:
            nextData = self.readData()
            if nextData == self.DATA_END:
                break;
            if status == Status.NONE:
                if nextData == -10:
                    status = Status.LINE
                elif nextData == -20:
                    status = Status.PAINT
                elif nextData == -30:
                    status = Status.LAST_PAINT
                else:
                    fileEnd = True
            elif status == Status.LINE:
                if nextData == -1:
                    status = Status.NONE
                else:
                    color = nextData
                    startX = self.readData()
                    if startX == -1:
                        status = Status.LINE # 0,-1 で来るパターンがある
                    else:
                        startY = self.readData()
                        #TODO:1ドット打つ
                        status = Status.LINE_NEXT
            elif status == Status.LINE_NEXT:
                if nextData <= self.endCheckValue:
                    status = Status.LINE
                else:
                    endX = nextData
                    endY = self.readData()
                    self.drawLine(int(startX * rateX) + self.offsetX, int(startY * rateY) + self.offsetY, int(endX * rateX) + self.offsetX,int(endY * rateY) + self.offsetY, color)
                    startX = endX
                    startY = endY
            elif status == Status.PAINT:
                if nextData <= self.endCheckValue:
                    status = Status.NONE
                else:
                    color = nextData
                    paintX = self.readData()
                    paintY = self.readData()
                    self.paint(int(paintX * rateX) + self.offsetX,int(paintY * rateY) + self.offsetY ,color)
                    status = Status.PAINT_NEXT

            elif status == Status.PAINT_NEXT:
                if nextData <= self.endCheckValue:
                    status = Status.PAINT
                else:
                    paintX = nextData
                    paintY = self.readData()
                    self.paint(int(paintX * rateX) + self.offsetX,int(paintY * rateY) + self.offsetY ,color)
            elif status == Status.LAST_PAINT:
                if nextData <= self.endCheckValue:
                    status = Status.NONE
                else:
                    color = nextData
                    startX = self.readData()
                    startY = self.readData()
                    endX = self.readData()
                    endY = self.readData()
                    self.lastPaint(int(startX * rateX) + self.offsetX,int(startY * rateY) + self.offsetY, \
                    int(endX * rateX) + self.offsetX,int(endY * rateY) + self.offsetY ,color)
                
            gc.collect()
            
        #self.testBuffer()    
        self.dataFile.close()
        if self.offsetX > 0:
            self.paint(0, 120, frameColor)
            self.paint(319, 120, frameColor)

        if  self.offsetY > 0:
            self.paint(160, 0, frameColor)
            self.paint(160, 239, frameColor)

        del self.currentFileLine
        del self.screenBuffer
        del self.dataFile
        gc.collect()
        #self.ledRed.duty(0)
        #self.ledGreen.duty(0)
        #self.ledBlue.duty(0) 
        for i in range(self.led_num):
            leds.set(i + 1, 0)
        
    def readData(self):
        while True: #値設定While
            while True: #ファイル1行読みこみWhile
                if len(self.currentFileLine) == 0:
                    self.currentFileLine = self.dataFile.readline().strip()
                    if self.currentFileLine :
                        #  "#"以降はコメント
                        commentIndex = self.currentFileLine.find("#")
                        if commentIndex != -1:
                            self.currentFileLine = self.currentFileLine[:commentIndex].strip()
                        if len(self.currentFileLine) > 1:
                            break
                    else:
                        return self.DATA_END
                else:
                    break
            #次のカンマの位置までを切り出す
            index = self.currentFileLine.find(",")
        
            if index == -1: #カンマ見つからず
                result = self.currentFileLine.strip()
                del self.currentFileLine
                gc.collect()    
                self.currentFileLine = ""
                if len(result) > 0:
                    return int(result,0)
            else:
                result = self.currentFileLine[:index].strip()
                self.currentFileLine = self.currentFileLine[index+1:].strip()
                if len(result) > 0:
                    return int(result,0)
                
    def drawLine(self,startX,startY,endX,endY,color):
        realStartX = startX
        realStartY = startY
        realEndX = endX
        realEndY = endY

        dx = abs(realEndX - realStartX)
        sx = 1 if realStartX < realEndX else -1
        dy = abs(realEndY - realStartY)
        sy = 1 if realStartY < realEndY else -1
        err = int((dx if dx > dy else -dy) / 2)
        
        while True:
            if realStartX >= 0 and realStartX < 320 and realStartY >=0 and realStartY < 240:
                lcd.pixel(realStartX,realStartY,color)
                self.screenBuffer.put(realStartX + realStartY * 320, True)
            
            if realStartX == realEndX and realStartY == realEndY:
                break
            
            e2 = err
            if e2 > -dx:
                err -= dy
                realStartX += sx
            
            if e2 < dy:
                err += dx
                realStartY += sy

    def paint(self,pixelX, pixelY, color):
        #バッファにある限りループ
          #int lx; /* 領域右端のX座標 */
          #int rx; /* 領域右端のX座標 */
          #int y;  /* 領域のY座標 */
          #int oy; /* 親ラインのY座標 */
        #Lチカ Colorの赤要素が、他の要素の2倍ある時だけLED ON
        #colorRed = (color & 0xFF0000) / 0x100 / 0x100
        #colorGreen = (color & 0x00FF00) / 0x100
        #colorBlue = (color & 0x0000FF)
        #print("R:" + str(colorRed) + ",G:" + str(colorGreen) + ",B:" + str(colorBlue) + "\n")
        #if colorRed > 30 and colorRed > (colorGreen + colorBlue):
        #        self.ledRed.duty(colorRed * 100 / 255)
        #self.ledGreen.duty(colorGreen * 100 / 255)
        #self.ledBlue.duty(colorBlue * 100 / 255) 

        for i in range(self.led_num):
            self.leds.set(i + 1, color)
          
          
        gPoint = {"lx":pixelX, "rx":pixelX ,"y":pixelY, "oy":pixelY}
        
        self.bufferList = [gPoint]

        while len(self.bufferList) > 0:
            checkPoint = self.bufferList.pop(0)
            lx = checkPoint["lx"]
            rx = checkPoint["rx"]
            ly = checkPoint["y"]
            oy = checkPoint["oy"]

            lxsav = lx - 1
            rxsav = rx + 1

            ##処理済みなら飛ばす
            if self.screenBuffer.get(lx + ly * 320) == True:
                continue
            
            ##右の境界を探す
            while rx < 319:
                if self.screenBuffer.get(rx + 1 + ly * 320) == True:
                    break
                rx = rx + 1

            ##左の境界を探す
            while lx > 0:
                if self.screenBuffer.get(lx - 1 + ly * 320) == True:
                    break
                lx = lx - 1

            ##lx から rx まで線を引く
            self.drawLine(lx, ly, rx, ly, color)
            gc.collect()

            ##真上のスキャンライン走査
            if ly - 1 >= 0:
                if ly - 1 == oy:
                    self.scanLine( lx, lxsav, ly -1 ,ly )
                    self.scanLine( rxsav, rx, ly -1 ,ly )
                else:
                    self.scanLine( lx, rx, ly -1 ,ly )
            
            ##真下のスキャンライン走査
            if ly + 1 <= 239:
                if ly + 1 == oy:
                    self.scanLine( lx, lxsav, ly + 1, ly)
                    self.scanLine( rxsav, rx, ly + 1, ly)
                else:
                    self.scanLine( lx, rx, ly +1, ly)
        #Lチカ
       # self.pinout.value(0)


    def scanLine(self, lx, rx, y, oy):
        templx = 0
        while lx <= rx:
            while lx < rx:
                if self.screenBuffer.get(lx + y * 320) == False:
                    break
                lx = lx + 1
                
            if self.screenBuffer.get(lx + y * 320) == True:
                break
            templx = lx

            while lx <= rx:
                if self.screenBuffer.get(lx + y * 320) == True:
                    break
                lx = lx + 1

            gPoint = {"lx":templx, "rx":lx - 1 ,"y":y, "oy":oy}
            if len(self.bufferList) < self.PAINT_BUFFER:
                self.bufferList.append(gPoint)

    #指定された矩形で、まだ塗っていない部分だけ塗る
    def lastPaint(self, startX, startY, endX, endY, color):
        print("lastPaint:" + str(startX) + ":"+ str(startY) +":"+  str(endX) +":"+  str(endY) )
        y = startY
        while y <= endY:
            x = startX            
            while x <= endX:
                if self.screenBuffer.get(x + y * 320) == False: 
                    lcd.pixel(x,y,color)
                x = x  + 1
            y = y + 1

    def testBuffer(self):
        for x in range(0,320):
            for y in range(0,240):
                if self.screenBuffer.get(x + y * 320) == True:
                     lcd.pixel(x,y,lcd.WHITE)
                else:                 
                     lcd.pixel(x,y,lcd.BLACK)
Ejemplo n.º 6
0
class Monitor(object):

    def __init__(
        self,
        solar_topic, grid_topic, mqtt_broker, wifi_credentials,
        graph_interval_s=60, update_interval_ms=1000
    ):
        self._solar_topic = solar_topic
        self._grid_topic = grid_topic
        self._mqtt_broker = mqtt_broker
        self._wifi_credentials = wifi_credentials
        self._graph_interval = graph_interval_s
        self._update_interval = update_interval_ms
        self._graph_window = Monitor._shorten(self._graph_interval * 320)

        self._tft = None
        self._wlan = None
        self._mqtt = None
        self._neopixel = None

        self._battery = IP5306(I2C(scl=Pin(22), sda=Pin(21)))
        self._timer = Timer(0)
        self._rtc = RTC()
        self._button_a = ButtonA(callback=self._button_a_pressed)
        self._button_b = ButtonB(callback=self._button_b_pressed)
        self._button_c = ButtonC(callback=self._button_c_pressed)

        self._reboot = False
        self._backup = False
        self._solar = None
        self._usage = None
        self._grid = None
        self._importing = None
        self._prev_importing = None
        self._solar_avg_buffer = []
        self._grid_avg_buffer = []
        self._usage_buffer = []
        self._usage_buffer_max = 0
        self._usage_buffer_min = 0
        self._usage_buffer_avg = 0
        self._usage_buffer_stddev = 0
        self._usage_max_coords = [0, 0]
        self._calculate_buffer_stats('usage', 0)
        self._solar_buffer = []
        self._solar_buffer_max = 0
        self._solar_buffer_min = 0
        self._solar_buffer_avg = 0
        self._solar_buffer_stddev = 0
        self._solar_max_coords = [0, 0]
        self._calculate_buffer_stats('solar', 0)
        self._last_update = (0, 0, 0, 0, 0, 0)
        self._data_received = [False, False]
        self._buffer_updated = False
        self._realtime_updated = False
        self._last_value_added = None
        self._graph_max = 0
        self._solar_max = 0
        self._usage_max = 0
        self._menu_horizontal_pointer = 0
        self._menu_tick = 0
        self._menu_tick_divider = 0
        self._blank_menu = False
        self._save = False
        self._show_markers = True
        self._color = None
        self._ticks = {'M': 0,  # MQTT message
                       'D': 0,  # Data sample (solar + grid)
                       'R': 0,  # Remaining time for next graph update
                       'G': 0,  # Graph datapoint added
                       'B': 0,  # Button press
                       'E': 0}  # Exceptions
        self._tick_keys = ['M', 'D', 'G', 'B', 'R', 'E']
        self._last_exception = 'None'
        self._runtime_config_parameters = ['show_markers']
        self._last_logline = ''

        self._log('Initializing TFT...')
        self._tft = display.TFT()
        self._tft.init(self._tft.M5STACK, width=240, height=320, rst_pin=33, backl_pin=32, miso=19, mosi=23, clk=18, cs=14, dc=27, bgr=True, backl_on=1)
        self._tft.tft_writecmd(0x21)  # Invert colors
        self._tft.clear()
        self._tft.font(self._tft.FONT_Default, transparent=False)
        self._tft.text(0, 0, 'USAGE', self._tft.DARKGREY)
        self._tft.text(self._tft.CENTER, 0, 'IMPORTING', self._tft.DARKGREY)
        self._tft.text(self._tft.RIGHT, 0, 'SOLAR', self._tft.DARKGREY)
        self._tft.text(0, 14, 'Loading...', self._tft.DARKGREY)
        self._log('Initializing TFT... Done')

    def init(self):
        """ Init logic; connect to wifi, connect to MQTT and setup RTC/NTP """
        self._log('Connecting to wifi ({0})... '.format(self._wifi_credentials[0]), tft=True)
        self._wlan = network.WLAN(network.STA_IF)
        self._wlan.active(True)
        self._wlan.connect(*self._wifi_credentials)
        safety = 10
        while not self._wlan.isconnected() and safety > 0:
            # Wait for the wifi to connect, max 10s
            time.sleep(1)
            safety -= 1
        self._log('Connecting to wifi ({0})... {1}'.format(self._wifi_credentials[0], 'Done' if safety else 'Fail'))
        mac_address = ubinascii.hexlify(self._wlan.config('mac'), ':').decode()
        self._log('Connecting to MQTT...', tft=True)
        if self._mqtt is not None:
            self._mqtt.unsubscribe('emon/#')
        self._mqtt = network.mqtt('emon', self._mqtt_broker, user='******', password='******', clientid=mac_address, data_cb=self._process_data)
        self._mqtt.start()
        safety = 5
        while self._mqtt.status()[0] != 2 and safety > 0:
            # Wait for MQTT connection, max 5s
            time.sleep(1)
            safety -= 1
        self._mqtt.subscribe('emon/#')
        self._log('Connecting to MQTT... {0}'.format('Done' if safety else 'Fail'))
        self._log('Sync NTP...', tft=True)
        self._rtc.ntp_sync(server='be.pool.ntp.org', tz='CET-1CEST-2')
        safety = 5
        while not self._rtc.synced() and safety > 0:
            # Wait for NTP time sync, max 5s
            time.sleep(1)
            safety -= 1
        self._last_update = self._rtc.now()
        self._log('Sync NTP... {0}'.format('Done' if safety else 'Fail'))
        self._log('Initializing Neopixels...', tft=True)
        try:
            self._neopixel = Neopixel(Pin(15), 10, Neopixel.TYPE_RGB)
            self._neopixel.clear()
        except Exception:
            self._neopixel = None
        self._log('Initializing Neopixels... {0}'.format('Available' if self._neopixel is not None else 'Unavailable'))
        self._tft.text(0, 14, ' ' * 50, self._tft.DARKGREY)  # Clear the line

    def _process_data(self, message):
        """ Process MQTT message """
        try:
            topic = message[1]
            data = float(message[2])
            self._ticks['M'] += 1

            # Collect data samples from solar & grid
            if topic == self._solar_topic:
                self._solar = max(0.0, data)
                self._data_received[0] = True
            elif topic == self._grid_topic:
                self._grid = data
                self._data_received[1] = True

            if self._data_received[0] and self._data_received[1]:
                self._ticks['D'] += 1
                # Once the data has been received, calculate realtime usage
                self._usage = self._solar + self._grid

                self._last_update = self._rtc.now()
                self._realtime_updated = True  # Redraw realtime values
                self._data_received = [False, False]

                # Process data for the graph; collect solar & grids, and every x-pixel
                # average the data out and draw them on that pixel.
                now = time.time()
                rounded_now = int(now - now % self._graph_interval)
                if self._last_value_added is None:
                    self._last_value_added = rounded_now
                self._ticks['R'] = int(rounded_now + self._graph_interval - now)
                self._solar_avg_buffer.append(int(self._solar))
                self._grid_avg_buffer.append(int(self._grid))
                if self._last_value_added != rounded_now:
                    self._ticks['G'] += 1
                    solar, usage = self._read_avg_buffer(reset=True)
                    self._solar_buffer.append(solar)
                    self._solar_buffer = self._solar_buffer[-319:]  # Keep one pixel for moving avg
                    self._calculate_buffer_stats('solar', solar)
                    self._usage_buffer.append(usage)
                    self._usage_buffer = self._usage_buffer[-319:]  # Keep one pixel for moving avg
                    self._calculate_buffer_stats('usage', usage)
                    self._last_value_added = rounded_now
                    self._buffer_updated = True  # Redraw the complete graph
        except Exception as ex:
            self._last_exception = str(ex)
            self._ticks['E'] += 1
            self._log('Exception in process data: {0}'.format(ex))

    def _calculate_buffer_stats(self, buffer_type, single_value):
        buffer = getattr(self, '_{0}_buffer'.format(buffer_type))
        if len(buffer) == 0:
            return
        setattr(self, '_{0}_buffer_max'.format(buffer_type), single_value if len(buffer) == 1 else max(*buffer))
        setattr(self, '_{0}_buffer_min'.format(buffer_type), single_value if len(buffer) == 1 else min(*buffer))
        setattr(self, '_{0}_buffer_avg'.format(buffer_type), sum(buffer) / len(buffer))
        setattr(self, '_{0}_buffer_stddev'.format(buffer_type), Monitor._stddev(buffer))

    def _read_avg_buffer(self, reset):
        solar_avg_buffer_length = len(self._solar_avg_buffer)
        grid_avg_buffer_length = len(self._grid_avg_buffer)
        if solar_avg_buffer_length == 0 or grid_avg_buffer_length == 0:
            return 0, 0
        solar = int(sum(self._solar_avg_buffer) / solar_avg_buffer_length)
        grid = int(sum(self._grid_avg_buffer) / grid_avg_buffer_length)
        usage = solar + grid
        if reset:
            self._solar_avg_buffer = []
            self._grid_avg_buffer = []
        return solar, usage

    def load(self):
        self._log('Loading runtime configuration...', tft=True)
        if 'runtime_config.json' in os.listdir('/flash'):
            with open('/flash/runtime_config.json', 'r') as f:
                runtime_config = ujson.load(f)
            for key in self._runtime_config_parameters:
                if key in runtime_config:
                    setattr(self, '_{0}'.format(key), runtime_config[key])
        self._log('Loading runtime configuration... Done', tft=True)
        self._log('Restoring backup...', tft=True)
        if 'backup.json' in os.listdir('/flash'):
            with open('/flash/backup.json', 'r') as f:
                backup = ujson.load(f)
            self._usage_buffer = backup.get('usage_buffer', [])
            self._calculate_buffer_stats('usage', 0)
            self._solar_buffer = backup.get('solar_buffer', [])
            self._calculate_buffer_stats('solar', 0)
            os.remove('/flash/backup.json')
        self._log('Restoring backup... Done', tft=True)

    def run(self):
        """ Set timer """
        self._timer.init(period=self._update_interval, mode=Timer.PERIODIC, callback=self._tick)

    def _tick(self, timer):
        """ Do stuff at a regular interval """
        _ = timer
        self._draw()
        try:
            # At every tick, make sure wifi is still connected
            if not self._wlan.isconnected():
                self.init()
        except Exception as ex:
            self._last_exception = str(ex)
            self._ticks['E'] += 1
            self._log('Exception in watchdog: {0}'.format(ex))
        if self._reboot:
            self._take_backup()
            self._save_runtime_config()
            machine.reset()
        if self._backup:
            self._take_backup()
            self._save_runtime_config()
            self._backup = False
        if self._save:
            self._save_runtime_config()
            self._save = False

    def _save_runtime_config(self):
        data = {}
        for key in self._runtime_config_parameters:
            data[key] = getattr(self, '_{0}'.format(key))
        with open('/flash/runtime_config.json', 'w') as runtime_config_file:
            runtime_config_file.write(ujson.dumps(data))

    def _take_backup(self):
        with open('/flash/backup.json', 'w') as backup_file:
            backup_file.write(ujson.dumps({'usage_buffer': self._usage_buffer,
                                           'solar_buffer': self._solar_buffer}))

    def _draw(self):
        """ Update display """
        try:
            self._draw_realtime()
        except Exception as ex:
            self._last_exception = str(ex)
            self._ticks['E'] += 1
            self._log('Exception in draw realtime: {0}'.format(ex))
        try:
            self._draw_graph()
        except Exception as ex:
            self._last_exception = str(ex)
            self._ticks['E'] += 1
            self._log('Exception in draw graph: {0}'.format(ex))
        try:
            self._draw_menu()
        except Exception as ex:
            self._last_exception = str(ex)
            self._ticks['E'] += 1
            self._log('Exception in draw menu: {0}'.format(ex))
        try:
            self._draw_rgb()
        except Exception as ex:
            self._last_exception = str(ex)
            self._ticks['E'] += 1
            self._log('Exception in draw rgb: {0}'.format(ex))

    def _draw_rgb(self):
        """ Uses the neopixel leds (if available) to indicate how "good" our power consumption is. """
        if self._neopixel is None:
            return
        if len(self._solar_buffer) == 0 or self._usage is None:
            self._neopixel.clear()
            return

        high_usage = self._usage > self._usage_buffer_avg + (self._usage_buffer_stddev * 2)
        if self._grid < 0:
            # Feeding back to the grid
            score = 0
            if self._grid < -500:
                score += 1
            if self._grid < -1000:
                score += 1
            if high_usage:
                score -= 1
            colors = [Neopixel.GREEN, Neopixel.LIME, Neopixel.YELLOW]
            color = colors[max(0, score)]
        else:
            score = 0
            if high_usage:
                score += 1
            if self._solar == 0:
                score += 1
            colors = [Neopixel.BLUE, Neopixel.PURPLE, Neopixel.RED]
            color = colors[max(0, score)]
        if self._color != color:
            self._neopixel.set(0, color, num=10)
            self._color = color

    def _draw_realtime(self):
        """ Realtime part; current usage, importing/exporting and solar """
        if not self._realtime_updated:
            return

        self._tft.text(self._tft.RIGHT, 14, '          {0:.2f}W'.format(self._solar), self._tft.YELLOW)
        self._tft.text(0, 14, '{0:.2f}W          '.format(self._usage), self._tft.BLUE)
        self._importing = self._grid > 0
        if self._prev_importing != self._importing:
            if self._importing:
                self._tft.text(self._tft.CENTER, 0, '  IMPORTING  ', self._tft.DARKGREY)
            else:
                self._tft.text(self._tft.CENTER, 0, '  EXPORTING  ', self._tft.DARKGREY)
        if self._importing:
            self._tft.text(self._tft.CENTER, 14, '  {0:.2f}W  '.format(abs(self._grid)), self._tft.RED)
        else:
            self._tft.text(self._tft.CENTER, 14, '  {0:.2f}W  '.format(abs(self._grid)), self._tft.GREEN)
        self._prev_importing = self._importing
        self._realtime_updated = False

    def _draw_graph(self):
        """ Draw the graph part """
        solar_moving_avg, usage_moving_avg = self._read_avg_buffer(reset=False)
        solar_max = max(self._solar_buffer_max, solar_moving_avg)
        usage_max = max(self._usage_buffer_max, usage_moving_avg)
        max_value = float(max(solar_max, usage_max))
        if max_value != self._graph_max:
            self._graph_max = max_value
            self._buffer_updated = True
        if solar_max != self._solar_max:
            self._solar_max = solar_max
            self._buffer_updated = True
        if usage_max != self._usage_max:
            self._usage_max = usage_max
            self._buffer_updated = True
        ratio = 1 if max_value == 0 else (180.0 / max_value)
        show_markers = self._show_markers and max_value > 0
        buffer_size = len(self._usage_buffer)

        avg_marker = False
        usage_max_coords = self._usage_max_coords
        solar_max_coords = self._solar_max_coords
        if self._buffer_updated:
            for index, usage in enumerate(self._usage_buffer):
                solar = self._solar_buffer[index]
                usage_y, solar_y = self._draw_graph_line(index, solar, usage, ratio)
                if usage == usage_max:
                    usage_max_coords = [index, usage_y]
                if solar == solar_max:
                    solar_max_coords = [index, solar_y]
        usage_y, solar_y = self._draw_graph_line(buffer_size, solar_moving_avg, usage_moving_avg, ratio)
        if usage_moving_avg == usage_max:
            avg_marker = True
            usage_max_coords = [buffer_size, usage_y]
        if solar_moving_avg == solar_max:
            avg_marker = True
            solar_max_coords = [buffer_size, solar_y]

        max_coords_changed = self._usage_max_coords != usage_max_coords or self._solar_max_coords != solar_max_coords
        if self._buffer_updated and max_coords_changed:
            self._tft.rect(buffer_size + 1, 40, 320, 220, self._tft.BLACK, self._tft.BLACK)
        if show_markers:
            self._draw_marker('{0:.0f}W'.format(solar_max), solar_max_coords, not avg_marker)
            self._draw_marker('{0:.0f}W'.format(usage_max), usage_max_coords, not avg_marker)
        self._usage_max_coords = usage_max_coords
        self._solar_max_coords = solar_max_coords
        self._buffer_updated = False

    def _draw_marker(self, text, coords, transparent):
        x, y = coords
        if x > 160:
            text_x = x - self._tft.textWidth(text) - 10
            line_start_x = x - 2
            line_end_x = x - 8
        else:
            text_x = x + 10
            line_start_x = x + 2
            line_end_x = text_x - 2
        if y > 120:
            text_y = y - 22
        else:
            text_y = y + 10
        self._tft.font(self._tft.FONT_Default, transparent=transparent)
        self._tft.text(text_x, text_y, text, self._tft.DARKGREY)
        self._tft.line(line_start_x, y, line_end_x, text_y + 6, self._tft.DARKGREY)
        self._tft.font(self._tft.FONT_Default, transparent=False)

    def _draw_graph_line(self, index, solar, usage, ratio):
        usage_height = int(usage * ratio)
        solar_height = int(solar * ratio)
        usage_y = 220 - usage_height
        solar_y = 220 - solar_height
        max_height = max(usage_height, solar_height)
        self._tft.line(index, 40, index, 220 - max_height, self._tft.BLACK)
        if usage_height > solar_height:
            self._tft.line(index, usage_y, index, solar_y, self._tft.BLUE)
            if solar_height > 0:
                self._tft.line(index, solar_y, index, 220, self._tft.DARKCYAN)
        else:
            self._tft.line(index, solar_y, index, usage_y, self._tft.YELLOW)
            if usage_height > 0:
                self._tft.line(index, usage_y, index, 220, self._tft.DARKCYAN)
        return usage_y, solar_y

    def _draw_menu(self):
        if self._blank_menu:
            self._tft.rect(0, 221, 320, 240, self._tft.BLACK, self._tft.BLACK)
            self._blank_menu = False
        if self._menu_horizontal_pointer == 0:
            data = 'Updated:  {0:04d}/{1:02d}/{2:02d} {3:02d}:{4:02d}:{5:02d}'.format(*self._last_update[:6])
        elif self._menu_horizontal_pointer == 1:
            data = 'Battery: {0}%'.format(self._battery.level)
        elif self._menu_horizontal_pointer == 2:
            data = 'Graph: {0} {1}, max {2:.2f}W'.format(len(self._usage_buffer), self._graph_window, self._graph_max)
        elif self._menu_horizontal_pointer in [3, 4]:
            data_type = 'solar' if self._menu_horizontal_pointer == 3 else 'usage'
            solar, usage = self._read_avg_buffer(reset=False)
            if self._menu_tick == 0:
                value = min(
                    getattr(self, '_{0}_buffer_min'.format(data_type)),
                    solar if data_type == 'solar' else usage,
                    self._solar if data_type == 'solar' else self._usage
                )
                info = 'min'
            elif self._menu_tick == 1:
                value = getattr(self, '_{0}_buffer_avg'.format(data_type))
                info = 'avg'
            elif self._menu_tick == 2:
                value = getattr(self, '_{0}_buffer_avg'.format(data_type)) + (getattr(self, '_{0}_buffer_stddev'.format(data_type)) * 2)
                info = 'high'
            else:
                value = max(
                    getattr(self, '_{0}_buffer_max'.format(data_type)),
                    solar if data_type == 'solar' else usage,
                    self._solar if data_type == 'solar' else self._usage
                )
                info = 'max'
            data = '{0}{1} stats: {2:.2f}W {3}'.format(data_type[0].upper(), data_type[1:], value, info)
        elif self._menu_horizontal_pointer == 5:
            data = 'Time: {0}'.format(time.time())
        elif self._menu_horizontal_pointer == 6:
            data = 'Exception: {0}'.format(self._last_exception[:20])
        elif self._menu_horizontal_pointer == 7:
            data = 'Press B to reboot'
        elif self._menu_horizontal_pointer == 8:
            data = 'Press B to take a backup'
        elif self._menu_horizontal_pointer == 9:
            data = 'Press B to {0} markers'.format('hide' if self._show_markers else 'show')
        elif self._menu_horizontal_pointer == 10:
            log_entry = self._last_logline[:26]
            if len(log_entry) < 26:
                log_entry += ' ' * (26 - len(log_entry))
            data = 'Log: {0}'.format(log_entry)
        else:
            data = 'Ticks: {0}'.format(', '.join('{0}'.format(self._ticks[key]) for key in self._tick_keys))
        self._tft.text(0, self._tft.BOTTOM, '<', self._tft.DARKGREY)
        self._tft.text(self._tft.RIGHT, self._tft.BOTTOM, '>', self._tft.DARKGREY)
        if len(data) < 32:
            padding = int(float(32 - len(data) + 1) / 2)
            data = '{0}{1}{2}'.format(' ' * padding, data, ' ' * padding)
        self._tft.text(self._tft.CENTER, self._tft.BOTTOM, data, self._tft.DARKGREY)
        self._menu_tick_divider += 1
        if self._menu_tick_divider == 3:  # Increase menu tick every X seconds
            self._menu_tick += 1
            if self._menu_tick == 4:
                self._menu_tick = 0
            self._menu_tick_divider = 0

    def _button_a_pressed(self, pin, pressed):
        _ = pin
        if pressed:
            self._ticks['B'] += 1
            self._menu_horizontal_pointer -= 1
            if self._menu_horizontal_pointer < 0:
                self._menu_horizontal_pointer = 11
            self._blank_menu = True

    def _button_b_pressed(self, pin, pressed):
        _ = pin
        if pressed:
            if self._menu_horizontal_pointer == 7:
                self._reboot = True
            elif self._menu_horizontal_pointer == 8:
                self._backup = True
            elif self._menu_horizontal_pointer == 9:
                self._show_markers = not self._show_markers
                self._save = True

    def _button_c_pressed(self, pin, pressed):
        _ = pin
        if pressed:
            self._ticks['B'] += 1
            self._menu_horizontal_pointer += 1
            if self._menu_horizontal_pointer > 11:
                self._menu_horizontal_pointer = 0
            self._blank_menu = True

    @staticmethod
    def _stddev(entries):
        """ returns the standard deviation of lst """
        avg = sum(entries) / len(entries)
        variance = sum([(e - avg) ** 2 for e in entries]) / len(entries)
        return sqrt(variance)

    @staticmethod
    def _shorten(seconds):
        """ Converts seconds to a `xh ym ys` notation """
        parts = []
        seconds_hour = 60 * 60
        seconds_minute = 60
        if seconds >= seconds_hour:
            hours = int((seconds - seconds % seconds_hour) / seconds_hour)
            seconds = seconds - (hours * seconds_hour)
            parts.append('{0}h'.format(hours))
        if seconds >= seconds_minute:
            minutes = int((seconds - seconds % seconds_minute) / seconds_minute)
            seconds = seconds - (minutes * seconds_minute)
            parts.append('{0}m'.format(minutes))
        if seconds > 0:
            parts.append('{0}s'.format(seconds))
        return ' '.join(parts)

    def _log(self, message, tft=False):
        """ Logs a message to the console and (optionally) to the display """
        print(message)
        self._last_logline = message
        if tft:
            self._tft.text(0, 14, '{0}{1}'.format(message, ' ' * 50), self._tft.DARKGREY)
Ejemplo n.º 7
0
from machine import I2C, Pin, Neopixel
import robot

time.sleep_ms(500)
np = Neopixel(Pin(27), 1) 
np.set(0,0x001000)  #green
np.show()  

neopixel_pin=27
pinsVbatt=[26,33,14,5,13]
pins3v=[4,12,2,15,0]
neopixel_pin=27
uart_pins=[16,17] #first 4 pin connecter

i2c_pins=[21,22] #2nd and 3rd 4 pin connector
i2c = I2C(sda=Pin(21), scl=Pin(22), freq=100000)
i2c.scan()
# i2c adressen:
#48 (=0x30): motor driver (im gehaeuse)
#104 (=0x68): MPU 6050 (accel/gyro/temp)
#41 (=0x29): vl53l0x

np.set(0,0x0000FF)  #blue?

from machine import PWM
servo = PWM(Pin(26),freq=50)
servo.duty(8)
time.sleep(1)
for i in range(5):
    np.set(0,0xFF0000)  #red
    np.show() 
Ejemplo n.º 8
0
R = Neopixel.RED
G = Neopixel.GREEN
B = Neopixel.BLUE
P = Neopixel.PURPLE
Y = Neopixel.YELLOW

######################################
# 2x BLUE: Script started
# blinking PUPRLE: Connecting to WiFi
# 1st GREEN: WiFi connected
# blinking YELLOW: syncing time
# 4x GREEN: boot process done
######################################

# Set up neopixel and turn off
np = Neopixel(Pin(26), 1, 0)
np.set(0,0,0,0)

for _ in range(2):
        np.set(0,B,0,0)
        time.sleep(0.1)
        np.set(0,0,0,0)

# Activate Wifi connection
wlan = WLAN(STA_IF)
wlan.active(True)


wlan.connect(<WIFI_SSID>, <WIFI_PASSWORD>, 5000)

while not wlan.isconnected():
R = Neopixel.RED
G = Neopixel.GREEN
B = Neopixel.BLUE
P = Neopixel.PURPLE
Y = Neopixel.YELLOW

######################################
# 2x BLUE: Script started
# blinking PUPRLE: Connecting to WiFi
# 1st GREEN: WiFi connected
# blinking YELLOW: syncing time
# 4x GREEN: boot process done
######################################

# Set up neopixel and turn off
np = Neopixel(Pin(26), 1, 0)
np.set(0,0,0,0)

for _ in range(2):
    np.set(0,B,0,0)
    time.sleep(0.1)
    np.set(0,0,0,0)

# Set up ADC for ACS712 sensor
acs712 = ADC(Pin(ADC5))
acs712.atten(ADC.ATTN_11DB)

# Capture start time
startTime = round(time.time())

# Check network connection
Ejemplo n.º 10
0
    'black': 0x000000,
    'red': 0xFF0000,
    'maroon': 0x800000,
    'yellow': 0xFFFF00,
    'olive': 0x808000,
    'lime': 0x00FF00,
    'green': 0x008000,
    'aqua': 0x00FFFF,
    'teal': 0x008080,
    'blue': 0x0000FF,
    'navy': 0x000080,
    'fuchsia': 0xFF00FF,
    'purple': 0x800080
}  #html colors

np = Neopixel(Pin(27), 1)  #one neopixel at pin 27
for c in colors:
    print('set neopixel 0 to {}'.format(c))
    np.set(0, colors[c])
    np.show()
    time.sleep(.5)

#sensors
#init i2c bus
i2c = I2C(sda=Pin(21), scl=Pin(22), freq=100000)
#distance sensor
from vl53l0x import VL53L0X
dist = VL53L0X(i2c)
dist.start()  #better performance (faster response, allows higher frequency)
# works up to ~1300 mm
# returns something >8000 if above.