From 84950373502068daff40afed5d8ae36ba63de0c1 Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Wed, 15 Dec 2021 18:17:53 +0200 Subject: [PATCH] First working copy - needs networking code and webserver --- boot.py | 1 - color.py | 1 - font.py | 36 +++++++- helpers.py | 112 +++++++++++++++++++++++ main.py | 53 ++++++++--- matrixclock/Display.py | 191 ++++++++++++++++++++++++++++++++++++++++ matrixclock/__init__.py | 1 + settings.py | 2 + 8 files changed, 378 insertions(+), 19 deletions(-) create mode 100644 helpers.py create mode 100644 matrixclock/Display.py create mode 100644 matrixclock/__init__.py create mode 100644 settings.py diff --git a/boot.py b/boot.py index e6f84d5..a2d8a71 100644 --- a/boot.py +++ b/boot.py @@ -8,4 +8,3 @@ import gc #webrepl.start() gc.collect() - diff --git a/color.py b/color.py index e36ca66..75cee70 100644 --- a/color.py +++ b/color.py @@ -5,4 +5,3 @@ Cyan25=(0,25,25) Yellow25=(25,25,0) Magenta25=(25,0,25) White25=(25,25,25) - diff --git a/font.py b/font.py index 9215b35..1badd67 100644 --- a/font.py +++ b/font.py @@ -1,5 +1,3 @@ -import pickle - font = { ' ':(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00), # '!':(0x00,0x00,0x00,0x00,0x07,0x00,0x0F,0x80,0x0F,0x80,0x0F,0x80,0x0F,0x80,0x0F,0x80,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00), # ! @@ -98,7 +96,7 @@ font = { '~':(0x00,0x00,0x00,0x00,0x1F,0x1C,0x3B,0x9C,0x39,0xDC,0x38,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00), # ~ }; -def Letter(Letter): +def Character(Letter): a=[] b=0 for i in range(0,32,2): @@ -110,5 +108,35 @@ def Letter(Letter): b+=1 return a +def CharacterColumn(Char,Column,Color=(24,24,25),ColorOff=(0,0,0)): #Default to change + Col=[ColorOff]*16 + for i in range(16): + c=(font[Char][i*2]<<8)+font[Char][i*2+1] + if c & 2**(15-Column) == 2**(15-Column): + Col[i]=Color + return Col - +# def CharacterColumn(Char,Column,Color=(24,24,25),ColorOff=(0,0,0)): #Default to change +# Col=[ColorOff]*16 +# a=[] +# b=0 +# for i in range(0,32,2): +# x="{:08b}".format(font[Char][i]) +# x+="{:08b}".format(font[Char][i+1]) +# if x[Column] == "1": +# Col[int(i/2)]=Color +# return Col + +# def CharacterColumn(Char,Column,Color=(24,24,25),ColorOff=(0,0,0)): #Default to change +# Col=[ColorOff]*16 +# for Pos in Character(Char): +# if Pos%16 == Column: +# Col[int(Pos/16)]=(Color) +# return Col + +def CharacterRow(Char,Row,Color=(24,24,25),ColorOff=(0,0,0)): #Default to change + Col=[ColorOff]*16 + for Pos in Character(Char): + if int(Pos/16) == Row: + Col[Pos%16]=(Color) + return Col \ No newline at end of file diff --git a/helpers.py b/helpers.py new file mode 100644 index 0000000..e9684ff --- /dev/null +++ b/helpers.py @@ -0,0 +1,112 @@ +import settings + +def Time2Sentence(TimeArray): + minute=TimeArray[4] + hour=(TimeArray[3]+settings.timezone)%24 + MinuteString=["", + "m1 past", + "m2 past", + "m3 past", + "m4 past", + "m5 past", + "m6 past", + "m7 past", + "m8 past", + "m9 past", + "m10 past", + "m11 past", + "m12 past", + "m13 past", + "m14 past", + "quarter past", + "m16 past", + "m17 past", + 'm18 past', + 'm19 past', + 'm20 past', + 'm20 m1 past', + 'm20 m2 past', + 'm20 m3 past', + 'm20 m4 past', + 'm20 m5 past', + 'm20 m6 past', + 'm20 m7 past', + 'm20 m8 past', + 'm20 m9 past', + 'half past', + 'm20 m9 to', + 'm20 m8 to', + 'm20 m7 to', + 'm20 m6 to', + 'm20 m5 to', + 'm20 m4 to', + 'm20 m3 to', + 'm20 m2 to', + 'm20 m1 to', + 'm20 to', + 'm19 to', + 'm18 to', + 'm17 to', + 'm16 to', + 'quarter to', + 'm14 to', + 'm13 to', + 'm12 to', + 'm11 to', + 'm10 to', + 'm9 to', + 'm8 to', + 'm7 to', + 'm6 to', + 'm5 to', + 'm4 to', + 'm3 to', + 'm2 to', + 'm1 to', + ] + HourString=['midnight', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'h7', + 'h8', + 'h9', + 'h10', + 'h11', + 'h12', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'h7', + 'h8', + 'h9', + 'h10', + 'h11', + 'midnight', + ] + + TimeString='it is' + TimeString += ' '+MinuteString[minute] + + if TimeString[-2:] == 'to': + TimeString += " "+HourString[hour+1] + else: + TimeString += " "+HourString[hour] + if minute == 0 and TimeString[-8:] != 'midnight': + TimeString += " oclock" + if 0 < hour < 12 and TimeString[-2:] != '12': + TimeString += " in the morning" + if 12 < hour <= 17: + TimeString += " in the afternoon" + if 17 < hour <= 21: + TimeString += " in the evening" + if 21 < hour <= 24 and TimeString[-8:] != 'midnight': + TimeString += " at night" + + return TimeString \ No newline at end of file diff --git a/main.py b/main.py index 2d4c090..0948d0d 100644 --- a/main.py +++ b/main.py @@ -1,19 +1,46 @@ import matrixclock import machine,neopixel -import font - +import settings +import ntptime +import network +import time +from helpers import Time2Sentence +import pickle +import random +def Test(Display,Speed=0,Type=1): + if Type == 1: + for h in range(24): + for m in range(60): + print(Time2Sentence((2021,12,4,h,m))) + Display.WriteSentence(Time2Sentence((2021,12,4,h,m)),(60,60,60)) + time.sleep(Speed) + if Type == 2: + for i in range(Display.number): + Display.np[i]=(255,255,255) + Display.np.write() + time.sleep(Speed) + Display.np[i]=(0,0,0) np=neopixel.NeoPixel(machine.Pin(14),16) -np[0]=(25,0,0) -np[2]=(25,25,0) -np[4]=(0,25,0) -np[6]=(0,25,25) -np[8]=(0,0,25) -np[10]=(25,0,25) -np[12]=(25,25,25) -np.write() +d=matrixclock.Display(14,16,16) +d.Clear() -d=matrixclock.display(14) -#d.clear() - +try: + SpecialDates=pickle.loads(bytearray("".join(open("SpecialDates.json").readlines()))) +except: + SpecialDates={} + +ntptime.settime() + +def DisplayTime(arg): + d.WriteSentence(Time2Sentence(time.localtime())) + +def ColorByTime(time): + return(random.getrandbits(8),random.getrandbits(8),random.getrandbits(8)) + + + +T=machine.Timer(-1) +#T.init(period=1000,mode=machine.Timer.PERIODIC,callback=DisplayTime) + diff --git a/matrixclock/Display.py b/matrixclock/Display.py new file mode 100644 index 0000000..c525787 --- /dev/null +++ b/matrixclock/Display.py @@ -0,0 +1,191 @@ +import machine,neopixel +from time import sleep #GOES +import font + +words={"it":[0,1], + "is":[3,4], + "beer":[19,35,51], + "m1":[13,14,15], + "m2":[16,17,18], + "m3":[48,49,50,51,52], + "m4":[44,45,46,47], + "m5":[32,33,34,35], + "m6":[73,74,75], + "m7":[96,97,98,99,100], + "m8":[88,89,90,91,92], + "m9":[54,55,56,57], + "m10":[20,21,22], + "m11":[37,38,39,40,41,42], + "m12":[80,81,82,83,84,85], + "m13":[24,25,26,27,28,29,30,31], + "m14":[64,65,66,67,68,69,70,71], + "quarter":[105,106,107,108,109,110,111], + "m16":[73,74,75,76,77,78,79], + "m17":[96,97,98,99,100,101,102,103,104], + "m18":[88,89,90,91,92,93,94,95], + "m19":[54,55,56,57,58,59,60,61], + "m20":[6,7,8,9,10,11], + "half":[112,113,114,115], + "past":[117,118,119,120], + "to":[120,121], + "h1":[150,151,152], + "h2":[153,154,155], + "h3":[132,133,134,135,136], + "h4":[140,141,142,143], + "h5":[156,157,158,159], + "h6":[137,138,139], + "h7":[123,124,125,126,127], + "h8":[128,129,130,131,132], + "h9":[169,170,171,172], + "h10":[167,168,169], + "h11":[176,177,178,179,180,181], + "h12":[144,145,146,147,148,149], + "midnight":[160,161,162,163,164,165,166,167], + "in":[192,193], + "the":[195,196,197], + "morning":[208,209,210,211,212,213,214], + "afternoon":[199,200,201,202,203,204,205,206,207], + "evening":[224,225,226,227,228,229,230], + "at":[216,217], + "night":[219,220,221,222,223], + "dot":[182,183,184], + "gin":[173,174,175], + "oclock":[185,187,188,189,190,191], + "and":[232,233,234], + "cold":[236,237,238,239], + "cool":[240,241,242,243], + "warm":[245,256,257,258], + "hot":[252,253,254], + "beer":[19,35,51,67], + } + +class Display(object): + """Initialises a NeoPixel-String.""" + def __init__(self,DataPin,Rows=16,Columns=16): + self.np=neopixel.NeoPixel(machine.Pin(DataPin),Rows*Columns) + self.number=Rows*Columns + self.Rows=Rows + self.Columns=Columns + + def Write(self,Pos,Colour=(0,0,0), Immediate=True): + """write(Pos,Colour=(0,0,0), Immediate=True): Writes a colour (given as an RGB triplet) to the Pixel + at position 'Pos'. If 'Immediate' is set, change immediately, otherwise, wait until the display is + explicitly written or a write with 'Immediate' is called.""" + if Pos >= self.number: + print("Out of range") + else: + self.np[self.Weave(Pos)]=Colour + if Immediate: + self.np.write() + + def Clear(self,color=(0,0,0),Immediate=True): + """Clears all pixels""" + for i in range(self.number): + self.np[i]=color + if Immediate: + self.np.write() + + def WriteWord(self,word,colour=(50,50,50),Immediate=False): + try: + for i in words[word]: + self.Write(i,colour,False) + if Immediate == True: + self.np.write() + except KeyError: + #print("No such word") + pass + + def WriteSentence(self,sentence,color=(25,25,0)): + self.Clear(Immediate=False) + for word in sentence.split(" "): + self.WriteWord(word,color,Immediate=False) + self.np.write() + + def Scroll(self,Direction,Fill=[(0,0,0)]*16): + newbuf=bytearray(b'') + if Direction == 'l': + for Row in range(0,self.Rows,2): + newbuf += self.np.buf[Row*16*3+3:Row*16*3+48] + newbuf+=bytearray([Fill[Row][1],Fill[Row][0],Fill[Row][2]]) + newbuf += bytearray([Fill[Row+1][1],Fill[Row+1][0],Fill[Row+1][2]]) + newbuf += self.np.buf[Row*16*3+48:Row*16*3+93] + self.np.buf=newbuf + self.np.write() + if Direction == 'r': + for Row in range(0,self.Rows): + for Col in range(self.Columns-1,0,-1): + self.WriteXY(Col,Row,self.GetXY(Col-1,Row),Immediate=False) + self.WriteXY(0,Row,Fill[Row],Immediate=False) + if Direction == 'd': + for Row in range(self.Rows-1,0,-1): + for Col in range(self.Columns): + self.WriteXY(Col,Row,self.GetXY(Col,Row-1),Immediate=False) + for Col in range(self.Columns): + self.WriteXY(Col,0,Fill[Col],Immediate=False) + if Direction == 'u': + for Row in range(0,self.Rows-1): + for Col in range(self.Columns): + self.WriteXY(Col,Row,self.GetXY(Col,Row+1),Immediate=False) + for Col in range(self.Columns): + self.WriteXY(Col,self.Rows-1,Fill[Col],Immediate=False) + self.np.write() + +# def Scroll(self,Direction,Fill=[(0,0,0)]*16): +# if Direction == 'l': +# for Row in range(0,self.Rows): +# for Col in range(0,self.Columns-1): +# self.WriteXY(Col,Row,self.GetXY(Col+1,Row),Immediate=False) +# #for Row in range(0,self.Rows): +# self.WriteXY(self.Columns-1,Row,Fill[Row],Immediate=False) +# if Direction == 'r': +# for Row in range(0,self.Rows): +# for Col in range(self.Columns-1,0,-1): +# self.WriteXY(Col,Row,self.GetXY(Col-1,Row),Immediate=False) +# self.WriteXY(0,Row,Fill[Row],Immediate=False) +# if Direction == 'd': +# for Row in range(self.Rows-1,0,-1): +# for Col in range(self.Columns): +# self.WriteXY(Col,Row,self.GetXY(Col,Row-1),Immediate=False) +# for Col in range(self.Columns): +# self.WriteXY(Col,0,Fill[Col],Immediate=False) +# if Direction == 'u': +# for Row in range(0,self.Rows-1): +# for Col in range(self.Columns): +# self.WriteXY(Col,Row,self.GetXY(Col,Row+1),Immediate=False) +# for Col in range(self.Columns): +# self.WriteXY(Col,self.Rows-1,Fill[Col],Immediate=False) +# self.np.write() + + def ScrollLetter(self,Direction,Text,Speed,Color=[(50,50,50)],BGColor=[(0,0,0)]): + for index,Letter in enumerate(Text): + for X in range(3,14): # FIXME: Adjust for x/y and direction + self.Scroll(Direction,font.CharacterColumn(Letter,X,Color[index%len(Color)],BGColor[index%len(BGColor)])) + sleep(Speed) + + def Num2Column(self,Number): + return(Number-int(Number/self.Columns)*self.Columns) + + def Num2Row(self,Number): + return(int(Number/self.Columns)) + + def Weave(self,Pos): + Row=self.Num2Row(Pos) + if Row%2 == 1: + NewPos=(Row+1)*self.Columns-self.Num2Column(Pos)-1 + else: + NewPos=Pos + return NewPos + + def WriteXY(self,X,Y,Color=(24,0,0),Immediate=True): + Pos=self.Write(Y*self.Columns+X,Color,Immediate) + + def GetXY(self,X,Y): + return self.np[self.XY2Num(X,Y)] + + def XY2Num(self,X,Y): + return self.Weave(Y*self.Columns+X) + + def TestPattern(self): + for i in range(256): + self.np[i]=(0,0,i) + self.np.write() \ No newline at end of file diff --git a/matrixclock/__init__.py b/matrixclock/__init__.py new file mode 100644 index 0000000..f0af3fa --- /dev/null +++ b/matrixclock/__init__.py @@ -0,0 +1 @@ +from matrixclock.Display import Display diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..d64c008 --- /dev/null +++ b/settings.py @@ -0,0 +1,2 @@ +timezone=2 +ssid="BLUEGROUND 856"