diff --git a/PyBasic/PyBasic README.txt b/PyBasic/PyBasic README.txt index 78ac527..2eea18b 100644 --- a/PyBasic/PyBasic README.txt +++ b/PyBasic/PyBasic README.txt @@ -1007,7 +1007,6 @@ control flow changes to the Program object, is used consistently throughout the * It is not possible to renumber a program. This would require considerable extra functionality. * Negative values are printed with a space (e.g. '- 5') in program listings because of tokenization. This does not affect functionality. -* Decimal values less than one must be expressed with a leading zero (i.e. 0.34 rather than .34) * User input values cannot be directly assigned to array variables in an **INPUT** or **READ** statement * Strings representing numbers (e.g. "10") can actually be assigned to numeric variables in **INPUT** and **READ** statements without an error, Python will silently convert them to integers. diff --git a/PyBasic/basicparser.py b/PyBasic/basicparser.py index 10b8f21..44d1bbf 100644 --- a/PyBasic/basicparser.py +++ b/PyBasic/basicparser.py @@ -680,11 +680,23 @@ def __openstmt(self): raise RuntimeError('File '+filename+' could not be opened in line ' + str(self.__line_number)) if accessMode == "r+": + if hasattr(self.__file_handles[filenum],'newlines'): + try: + self.__file_handles[filenum].readline() + except: + pass + newlines = self.__file_handles[filenum].newlines + else: + newlines = None self.__file_handles[filenum].seek(0) filelen = 0 for lines in self.__file_handles[filenum]: - filelen += (len(lines)+(0 if uname()[0].upper() == 'LINUX' or \ - implementation.name.upper() in ['MICROPYTHON','CIRCUITPYTHON'] else 1)) + filelen += len(lines) + if newlines != None: + filelen += len(newlines)-1 + else: + filelen += (0 if uname()[0].upper() == 'LINUX' or \ + implementation.name.upper() in ['MICROPYTHON','CIRCUITPYTHON'] else 1) self.__file_handles[filenum].seek(filelen) diff --git a/PyBasic/lexer.py b/PyBasic/lexer.py index b2576c5..d347bea 100644 --- a/PyBasic/lexer.py +++ b/PyBasic/lexer.py @@ -99,9 +99,13 @@ def tokenize(self, stmt): break # Process numbers - elif c.isdigit(): - token.category = Token.UNSIGNEDINT - found_point = False + elif c.isdigit() or c == ".": + if c == ".": + token.category = Token.UNSIGNEDFLOAT + found_point = True + else: + token.category = Token.UNSIGNEDINT + found_point = False # Consume all of the digits, including any decimal point while True: diff --git a/PyBasic/program.py b/PyBasic/program.py index 0b5806a..a7e22e3 100644 --- a/PyBasic/program.py +++ b/PyBasic/program.py @@ -146,13 +146,26 @@ def load(self, file, tmpfile): try: infile = open(file, 'r') + if hasattr(infile,'newlines'): + try: + infile.readline() + except: + pass + newlines = infile.newlines + infile.seek(0) + else: + newlines = None fIndex = 0 fOffset = 0 pgmLoad = False if file.split(".")[-1].upper() == "PGM": pgmLoad = True for fileLine in infile: - fOffset += (len(fileLine) + (0 if self.__imp == 'X' else 1)) + fOffset += len(fileLine) + if newlines != None: + fOffset += len(newlines)-1 + elif self.__imp != 'X': + fOffset += 1 if len(fileLine) >= 9 and fileLine[0:9] == "-999,-999": break @@ -173,8 +186,11 @@ def load(self, file, tmpfile): if fileLine.strip().upper()[fileLine.strip().find(' '):].strip()[:4] == "DATA": self.__data.addData(line_number,fIndex) #self.add_stmt(Lexer().tokenize((fileLine.replace("\n","")).replace("\r","")),fIndex+fOffset,tmpfile) - fIndex += (len(fileLine) + (0 if self.__imp == 'X' else 1)) - + fIndex += len(fileLine) + if newlines != None: + fIndex += len(newlines)-1 + elif self.__imp != 'X': + fIndex += 1 except OSError: print("Could not read file") @@ -204,10 +220,22 @@ def add_stmt(self, tokenlist, fIndex, tmpfile): if tokenlist[1].lexeme == "DATA": self.__data.addData(line_number,fIndex) else: + if hasattr(tmpfile,'newlines'): + try: + tmpfile.readline() + except: + pass + newlines = tmpfile.newlines + else: + newlines = None tmpfile.seek(0) filelen = 0 for lines in tmpfile: - filelen += (len(lines)+(0 if self.__imp == 'X' else 1)) + filelen += len(lines) + if newlines != None: + filelen += len(newlines) - 1 + elif self.__imp != 'X': + filelen += 1 self.__program[line_number] = -(filelen+1) if tokenlist[1].lexeme == "DATA": diff --git a/PyDOS.py b/PyDOS.py index 5433e10..b71d065 100644 --- a/PyDOS.py +++ b/PyDOS.py @@ -73,7 +73,7 @@ def PyDOS(): global envVars if "envVars" not in globals().keys(): envVars = {} - _VER = "1.43" + _VER = "1.51" prmpVals = ['>','(',')','&','|','\x1b','\b','<','=',' ',_VER,'\n','$',''] print("Starting Py-DOS...") @@ -629,6 +629,8 @@ def readBATFile(BATfile): (validPath,tmpDir) = chkPath(aPath) if cmd in ["DELETE","DEL","TYPE","MORE","MKDIR","MD"]: tmpDir = pFmt(tmpDir) + else: + tmpDir = pFmt(tmpDir,False) if cmd == "" or cmd == "REM": continue diff --git a/README.md b/README.md index 4857417..f14caba 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,10 @@ down - the number of tiles connected down the matrix display If the parameters are omitted or not properly formatted, the program will prompt for each of the values. -**Playimage.py [filename]** - (Circuitpython only, requires the adafruit_imageload library installed in the /lib folder) program to display .bmp, .jpg, .gif or .png image files. If the program is loaded from PyDOS it attempts to determine the appropriate display configuration from the PyDOS environment, otherwise several display options are supported and selected depending on the existence of BOARD.Display or locally installed display libraries. +**Playimage.py [filename[,filename2,filename3,etc[],seconds_to_display]]]** - (Circuitpython only, requires the adafruit_imageload library installed in the /lib folder) program to display .bmp, .jpg, .gif (incl animated) or .png image files. If multiple comma +seperated files are entered a continous slide show is displayed with each image being +displayed for `seconds_to_display` seconds. Wildcard's in the format of *.xxx can be used +as an input filename. If the program is loaded from PyDOS it attempts to determine the appropriate display configuration from the PyDOS environment, otherwise several display options are supported and selected depending on the existence of BOARD.DISPLAY or locally installed display libraries. **reboot.py** - performs a soft reboot (Micropython requires a Ctrl-D to complete) diff --git a/bounce.py b/bounce.py index 2f06d3d..374d409 100644 --- a/bounce.py +++ b/bounce.py @@ -8,7 +8,8 @@ Pydos_ui = None x = 10; y = 10; d = 1; e = 1 -m='⬤' +#m='⬤' +m='O' try: width = int(envVars.get('_scrWidth',80)) height = int(envVars.get('_scrHeight',24)) diff --git a/cpython/boardconfigs/pydos_bcfg_waveshare_esp32_s3_geek.py b/cpython/boardconfigs/pydos_bcfg_waveshare_esp32_s3_geek.py new file mode 100644 index 0000000..d7e2d96 --- /dev/null +++ b/cpython/boardconfigs/pydos_bcfg_waveshare_esp32_s3_geek.py @@ -0,0 +1,14 @@ +import board + +Pydos_pins = { + 'SCL' : (board.SCL,"SCL GP17"), + 'SDA' : (board.SDA,"SDA GP16"), +# SDIO is faster +# 'SCK' : [(board.SD_SCK,"SD_SCK GP36")], +# 'MOSI' : [(board.SD_MOSI,"SD_MOSI GP36")], +# 'MISO' : [(board.SD_MISO,"SD_MISO GP37")], +# 'CS' : [(board.SD_CS,"SD_CS GP34")], + 'SDIO_CLK' : (board.GP36,"GP36"), + 'SDIO_CMD' : (board.GP35,"GP35"), + 'SDIO_DPINS' : ([board.GP37, board.GP33, board.GP38, board.GP34],"[GP37, GP33, GP38, GP34]") +} diff --git a/cpython/kbdFeatherWing/factory_test.py b/cpython/kbdFeatherWing/factory_test.py index a969054..a5eed6d 100644 --- a/cpython/kbdFeatherWing/factory_test.py +++ b/cpython/kbdFeatherWing/factory_test.py @@ -4,6 +4,7 @@ import adafruit_sdcard import digitalio import displayio +import fourwire import neopixel import storage import board @@ -28,7 +29,7 @@ sd_cs = board.D5 neopix_pin = board.D11 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240) print('Display: Pass? (you tell me)') diff --git a/cpython/kbdFeatherWing/lib/pydos_ui_kfw.py b/cpython/kbdFeatherWing/lib/pydos_ui_kfw.py index ec9d617..3912569 100644 --- a/cpython/kbdFeatherWing/lib/pydos_ui_kfw.py +++ b/cpython/kbdFeatherWing/lib/pydos_ui_kfw.py @@ -29,6 +29,7 @@ import adafruit_ili9341 import displayio +import fourwire class PyDOS_UI: @@ -42,7 +43,7 @@ def __init__(self): _tft_cs = board.D9 _tft_dc = board.D10 - _display_bus = displayio.FourWire(Pydos_hw.SPI(), command=_tft_dc, chip_select=_tft_cs) + _display_bus = fourwire.FourWire(Pydos_hw.SPI(), command=_tft_dc, chip_select=_tft_cs) _display = adafruit_ili9341.ILI9341(_display_bus, width=320, height=240) self.kbd = BBQ10Keyboard(Pydos_hw.I2C(),BBQI2CDevice=Pydos_hw.I2CbbqDevice) diff --git a/cpython/matrix.py b/cpython/matrix.py index 4d22d19..a7926c0 100644 --- a/cpython/matrix.py +++ b/cpython/matrix.py @@ -6,13 +6,19 @@ import framebufferio import rgbmatrix import supervisor +from os import getenv try: type(passedIn) +except: + passedIn = getenv('PYDOS_MATRIX_CONFIG') + +try: args = passedIn.split(',') [base_width,base_height,bit_depth,chain_across,tile_down] = [int(p) for p in args] except: passedIn = "" + args = "" if len(args) != 5 or args[0] not in ['32','64'] or args[1] not in ['32','64'] or bit_depth < 1 or bit_depth > 8: try: diff --git a/cpython/playimage.py b/cpython/playimage.py index 8288f5c..09a4c7b 100644 --- a/cpython/playimage.py +++ b/cpython/playimage.py @@ -3,13 +3,26 @@ import gifio except: pass +import adafruit_ticks import adafruit_imageload import bitmaptools import displayio -import time +try: + import fourwire +except + pass from os import getenv +from supervisor import runtime try: from pydos_ui import Pydos_ui + readkbd = Pydos_ui.read_keyboard + sba = Pydos_ui.serial_bytes_available +except: + Pydos_ui = [] + from sys import stdin + readkbd = stdin.read + sba = lambda : runtime.serial_bytes_available +try: from pydos_ui import input Pydos_display = ('display' in dir(Pydos_ui)) except: @@ -19,28 +32,32 @@ type(envVars) except: envVars = {} - + +display = None if '_display' in envVars.keys(): display = envVars['_display'] elif Pydos_display: display = Pydos_ui.display -elif 'DISPLAY' in dir(board): +elif bool(getattr(board,'DISPLAY',False)): display = board.DISPLAY +elif bool(getattr(runtime,'display',False)): + display = runtime.display else: try: - import matrix - display = matrix.envVars['_display'] + import framebufferio + import dotclockframebuffer except: try: - import framebufferio - import dotclockframebuffer + import adafruit_ili9341 except: try: - import adafruit_ili9341 - except: - import framebufferio + # import framebufferio import picodvi + except: + import matrix + display = matrix.envVars['_display'] + if display == None: displayio.release_displays() if 'TFT_PINS' in dir(board): @@ -66,7 +83,7 @@ spi = board.SPI() else: spi = busio.SPI(clock=board.SCK,MOSI=board.MOSI,MISO=board.MISO) - disp_bus=displayio.FourWire(spi,command=board.D10,chip_select=board.D9, \ + disp_bus=fourwire.FourWire(spi,command=board.D10,chip_select=board.D9, \ reset=board.D6) display=adafruit_ili9341.ILI9341(disp_bus,width=320,height=240) except: @@ -79,88 +96,78 @@ def playimage(passedIn=""): if passedIn != "": - fname = passedIn + flist = passedIn else: - fname = "" + flist = "" - if fname == "": - fname = input("Enter filename: ") + if flist == "": + flist = input("Enter filename: ") try: while Pydos_ui.virt_touched(): pass except: pass - if fname==passedIn: + if flist==passedIn: print('Press "q" to quit') else: input('Press "Enter" to continue, press "q" to quit') - if fname[-4:].upper() in [".BMP",".PNG",".JPG",".RLE"]: + files = flist.split(',') + try: + dispseconds = int(files[-1]) + files = files[:-1] + except: + dispseconds = 15 - bitmap, palette = adafruit_imageload.load( \ - fname, bitmap=displayio.Bitmap, palette=displayio.Palette) - - scalefactor = display.width / bitmap.width - if display.height/bitmap.height < scalefactor: - scalefactor = display.height/bitmap.height + singleimage = False + if len(files) == 1 and files[0][0] != '*': + singleimage = True - if scalefactor < 1: - print(f'scalefactor: {scalefactor}') - bitframe = displayio.Bitmap(display.width,display.height,2**bitmap.bits_per_value) - bitmaptools.rotozoom(bitframe,bitmap,scale=scalefactor) - facecc = displayio.TileGrid(bitframe,pixel_shader=palette) - # pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) - pwidth = bitframe.width - pheight = bitframe.height - else: - facecc = displayio.TileGrid(bitmap,pixel_shader=palette) - # pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) - pwidth = bitmap.width - pheight = bitmap.height - - print("bitmap (w,h): ",bitmap.width,bitmap.height) - print("scaled bitmap (w,h): ",pwidth,pheight) - print("facecc (w,h): ",facecc.width,facecc.height) - - if pwidth < display.width: - facecc.x = (display.width-pwidth)//2 - if pheight < display.height: - facecc.y = (display.height-pheight)//2 - splash = displayio.Group() - splash.append(facecc) - display.root_group = splash + fileindx = 0 + wildindx = 0 + while True: + fname = files[fileindx] - input('Press Enter to close') + if fname[0] == '*': + wildlist = [f for f in os.listdir() if f[fname.find('.')-len(fname):] == fname[fname.find('.')-len(fname):]] + fname = wildlist[wildindx] + wildindx = (wildindx +1) % len(wildlist) + if wildindx == 0: + fileindx = (fileindx + 1) % len(files) + else: + fileindx = (fileindx + 1) % len(files) - elif fname[-4:].upper() in [".GIF"]: - odgcc = gifio.OnDiskGif(fname) - with odgcc as odg: + if fname[-4:].upper() in [".BMP",".PNG",".JPG",".RLE"]: - if getenv('PYDOS_DISPLAYIO_COLORSPACE',"").upper() == 'BGR565_SWAPPED': - colorspace = displayio.Colorspace.BGR565_SWAPPED - else: - colorspace = displayio.Colorspace.RGB565_SWAPPED - - scalefactor = display.width / odg.width - if display.height/odg.height < scalefactor: - scalefactor = display.height/odg.height + bitmap, palette = adafruit_imageload.load( \ + fname, bitmap=displayio.Bitmap, palette=displayio.Palette) + + scalefactor = display.width / bitmap.width + if display.height/bitmap.height < scalefactor: + scalefactor = display.height/bitmap.height if scalefactor < 1: - print(f'scalefactor: {scalefactor}') - bitframe = displayio.Bitmap(display.width,display.height,2**odg.bitmap.bits_per_value) - bitmaptools.rotozoom(bitframe,odg.bitmap,scale=scalefactor) - facecc = displayio.TileGrid(bitframe, \ - pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) + if singleimage: + print(f'scalefactor: {scalefactor}') + bitframe = displayio.Bitmap(display.width,display.height,2**bitmap.bits_per_value) + bitmaptools.rotozoom(bitframe,bitmap,scale=scalefactor) + facecc = displayio.TileGrid(bitframe,pixel_shader=palette) + # pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) pwidth = bitframe.width pheight = bitframe.height else: - facecc = displayio.TileGrid(odg.bitmap, \ - pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) - pwidth = odg.bitmap.width - pheight = odg.bitmap.height + facecc = displayio.TileGrid(bitmap,pixel_shader=palette) + # pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) + pwidth = bitmap.width + pheight = bitmap.height + if singleimage: + print("bitmap (w,h): ",bitmap.width,bitmap.height) + print("scaled bitmap (w,h): ",pwidth,pheight) + print("facecc (w,h): ",facecc.width,facecc.height) + if pwidth < display.width: facecc.x = (display.width-pwidth)//2 if pheight < display.height: @@ -169,27 +176,104 @@ def playimage(passedIn=""): splash.append(facecc) display.root_group = splash - start = 0 - next_delay = -1 - cmnd = "" - # Display repeatedly. - while cmnd.upper() != "Q": - - if Pydos_ui.serial_bytes_available(): - cmnd = Pydos_ui.read_keyboard(1) - print(cmnd, end="", sep="") - if cmnd in "qQ": - break - while time.monotonic() > start and next_delay > time.monotonic()-start: - pass - next_delay = odg.next_frame() - start = time.monotonic() - if next_delay > 0: - if scalefactor < 1: - bitmaptools.rotozoom(bitframe,odg.bitmap,scale=scalefactor) + if singleimage: + input('Press Enter to close') + break + else: + cmnd = "" + stop = adafruit_ticks.ticks_add(adafruit_ticks.ticks_ms(),int(dispseconds*1000)) + while adafruit_ticks.ticks_less(adafruit_ticks.ticks_ms(),stop): + if sba(): + cmnd = readkbd(1) + print(cmnd, end="", sep="") + if cmnd.upper() == "Q": + break + if cmnd.upper() == "Q": + break - else: - print('Unknown filetype') + try: + splash.pop() + bitmap.deinit() + bitmap = None + facecc.bitmap.deinit() + facecc = None + if scalefactor < 1: + bitframe.deinit() + bitframe = None + except: + pass + + elif fname[-4:].upper() in [".GIF"]: + + odgcc = gifio.OnDiskGif(fname) + with odgcc as odg: + + if getenv('PYDOS_DISPLAYIO_COLORSPACE',"").upper() == 'BGR565_SWAPPED': + colorspace = displayio.Colorspace.BGR565_SWAPPED + else: + colorspace = displayio.Colorspace.RGB565_SWAPPED + + scalefactor = display.width / odg.width + if display.height/odg.height < scalefactor: + scalefactor = display.height/odg.height + + if scalefactor < 1: + if singleimage: + print(f'scalefactor: {scalefactor}') + bitframe = displayio.Bitmap(display.width,display.height,2**odg.bitmap.bits_per_value) + bitmaptools.rotozoom(bitframe,odg.bitmap,scale=scalefactor) + facecc = displayio.TileGrid(bitframe, \ + pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) + pwidth = bitframe.width + pheight = bitframe.height + else: + facecc = displayio.TileGrid(odg.bitmap, \ + pixel_shader=displayio.ColorConverter(input_colorspace=colorspace)) + pwidth = odg.bitmap.width + pheight = odg.bitmap.height + + if pwidth < display.width: + facecc.x = (display.width-pwidth)//2 + if pheight < display.height: + facecc.y = (display.height-pheight)//2 + splash = displayio.Group() + splash.append(facecc) + display.root_group = splash + + cmnd = "" + # Display repeatedly. + stop = adafruit_ticks.ticks_add(adafruit_ticks.ticks_ms(),int(dispseconds*1000)) + while adafruit_ticks.ticks_less(adafruit_ticks.ticks_ms(),stop) or singleimage: + + if sba(): + cmnd = readkbd(1) + print(cmnd, end="", sep="") + if cmnd.upper() == "Q": + break + start = adafruit_ticks.ticks_ms() + next_delay = odg.next_frame() + start = adafruit_ticks.ticks_add(start,int(next_delay*1000)) + if next_delay > 0: + if scalefactor < 1: + bitmaptools.rotozoom(bitframe,odg.bitmap,scale=scalefactor) + while adafruit_ticks.ticks_less(adafruit_ticks.ticks_ms(),start): + pass + if cmnd.upper() == "Q": + break + + try: + splash.pop() + odgcc = None + facecc.bitmap.deinit() + facecc = None + if scalefactor < 1: + bitframe.deinit() + bitframe = None + except: + pass + + else: + print('Unknown filetype') try: splash.pop() diff --git a/edit.py b/edit.py index 2994431..f55563a 100644 --- a/edit.py +++ b/edit.py @@ -1,4 +1,4 @@ -from pye_gen import pye +from pye_pydos import pye if __name__ != "PyDOS": passedIn = "" diff --git a/fileview.py b/fileview.py index d51472c..c6c56f0 100644 --- a/fileview.py +++ b/fileview.py @@ -1,12 +1,23 @@ import os -from pydos_ui import Pydos_ui +import supervisor +from sys import implementation +try: + from pydos_ui import Pydos_ui + readkbd = Pydos_ui.read_keyboard +except: + Pydos_ui = None + from sys import stdin + readkbd = stdin.read try: from pydos_ui import input except: pass #import uselect -def viewFile(args): +def viewFile(args,scrsiz=()): + # scrsiz can be used if running program from REPL to specify the screen dimensions + # first import launches with defaults but subsequent launches can use: + # fileview.viewFile("filename.txt",(height,width)) def chkPath(tstPath): validPath = True @@ -60,19 +71,34 @@ def absolutePath(argPath,currDir): scrLines = int(envVars["_scrHeight"]) scrWidth = int(envVars["_scrWidth"]) + elif scrsiz: + (scrLines,scrWidth) = scrsiz elif 'get_screensize' in dir(Pydos_ui): (scrLines,scrWidth) = Pydos_ui.get_screensize() else: - scrLines = 24 - scrWidth = 80 + if 'height' in dir(supervisor.runtime.display): + scrLines = supervisor.runtime.display.height + scrWidth = supervisor.runtime.display.width + else: + scrLines = 24 + scrWidth = 80 + + try: + type(envVars) + except: + envVars={} if "_scrollable" in envVars.keys(): - scrollable = (envVars["_scrollable"] == True) + scrollable = (envVars["_scrollable"] == True) or (envVars["_scrollable"] == "True") else: try: scrollable = Pydos_ui.scrollable except: - scrollable = False + if implementation.name.upper() == 'CIRCUITPYTHON': + # Once CircuitPython 9.2.4 is stable this can be change to True + scrollable = False + else: + scrollable = False savDir = os.getcwd() args = absolutePath(args,savDir) @@ -107,8 +133,7 @@ def absolutePath(argPath,currDir): seqCnt = 0 strtCol = 0 while cmnd.upper() != "Q": - #cmnd = kbdInterrupt() - cmnd = Pydos_ui.read_keyboard(1) + cmnd = readkbd(1) if ord(cmnd) == 27 and seqCnt == 0: seqCnt = 1 diff --git a/getdate.py b/getdate.py index 5f1b7a2..7e8a41a 100644 --- a/getdate.py +++ b/getdate.py @@ -28,32 +28,7 @@ def getdate(passedIn=""): print("Attempting to set Date/Time",end="") try: - print(" Using http worldtimeapi.org...",end="") - response = Pydos_wifi.get("http://worldtimeapi.org/api/ip",None,True) - time_data = Pydos_wifi.json() - - if passedIn == "": - tz_hour_offset = int(time_data['utc_offset'][0:3]) - tz_min_offset = int(time_data['utc_offset'][4:6]) - if (tz_hour_offset < 0): - tz_min_offset *= -1 - else: - tz_hour_offset = int(passedIn) - tz_min_offset = 0 - - unixtime = int(time_data['unixtime'] + (tz_hour_offset * 60 * 60)) + (tz_min_offset * 60) - ltime = time.localtime(unixtime) - - if sys.implementation.name.upper() == "MICROPYTHON": - machine.RTC().datetime(tuple([ltime[0]-(time.localtime(0)[0]-1970)]+[ltime[i] for i in [1,2,6,3,4,5,7]])) - else: - rtc.RTC().datetime = ltime - - print("\nTime and Date successfully set",end="") - envVars['errorlevel'] = '0' - - except: - print( " FAILED. Trying NTP...",end="") + print( "Trying NTP...",end="") if passedIn == "": tz_hour_offset = -4 @@ -116,6 +91,33 @@ def getdate(passedIn=""): print("\nTime and Date successfully set",end="") envVars['errorlevel'] = '0' + except: + + print("FAILED. Trying http worldtimeapi.org...",end="") + Pydos_wifi.timeout = 1000 + response = Pydos_wifi.get("http://worldtimeapi.org/api/ip",None,True) + time_data = Pydos_wifi.json() + + if passedIn == "": + tz_hour_offset = int(time_data['utc_offset'][0:3]) + tz_min_offset = int(time_data['utc_offset'][4:6]) + if (tz_hour_offset < 0): + tz_min_offset *= -1 + else: + tz_hour_offset = int(passedIn) + tz_min_offset = 0 + + unixtime = int(time_data['unixtime'] + (tz_hour_offset * 60 * 60)) + (tz_min_offset * 60) + ltime = time.localtime(unixtime) + + if sys.implementation.name.upper() == "MICROPYTHON": + machine.RTC().datetime(tuple([ltime[0]-(time.localtime(0)[0]-1970)]+[ltime[i] for i in [1,2,6,3,4,5,7]])) + else: + rtc.RTC().datetime = ltime + + print("\nTime and Date successfully set",end="") + envVars['errorlevel'] = '0' + print() Pydos_wifi.close() diff --git a/lib/pydos_bcfg.py b/lib/pydos_bcfg.py index 92ce74e..bf659c4 100644 --- a/lib/pydos_bcfg.py +++ b/lib/pydos_bcfg.py @@ -47,7 +47,7 @@ from machine import Pin try: led = "LED" - test = machine.Pin(led,Pin.OUT) + test = Pin(led,Pin.OUT) except: led = "D13" diff --git a/lib/pydos_ui.py b/lib/pydos_ui.py index 64e8211..638a1f0 100644 --- a/lib/pydos_ui.py +++ b/lib/pydos_ui.py @@ -6,6 +6,7 @@ import select if implementation.name.upper() == "CIRCUITPYTHON": import board + from supervisor import runtime try: from displayio import CIRCUITPYTHON_TERMINAL as TERM from terminalio import FONT @@ -15,8 +16,15 @@ class PyDOS_UI: def __init__(self): - if implementation.name.upper() == "CIRCUITPYTHON" and 'DISPLAY' in dir(board): + if implementation.name.upper() == "CIRCUITPYTHON": + self.scrollable = False + if bool(getattr(board,'DISPLAY',False)): + self.display = board.DISPLAY + elif bool(getattr(runtime,'display',False)): + self.display = runtime.display + else: + self.scrollable = True else: self.scrollable = True @@ -32,7 +40,6 @@ def serial_bytes_available(self,timeout=1): retval = 0 else: retval = 1 - retval = 1 if retval else 0 return retval @@ -46,8 +53,8 @@ def get_screensize(self,disp=None): dhigh = disp.height dwide = disp.width else: - dhigh = board.DISPLAY.height - dwide = board.DISPLAY.width + dhigh = self.display.height + dwide = self.display.width height = round(dhigh/(FONT.bitmap.height*TERM.scale))-1 width = round(dwide/((FONT.bitmap.width/95)*TERM.scale))-2 diff --git a/lib/pydos_wifi.py b/lib/pydos_wifi.py index 53a6f88..78db3c2 100644 --- a/lib/pydos_wifi.py +++ b/lib/pydos_wifi.py @@ -1,4 +1,4 @@ -PyDOS_wifi_VER = "1.40" +PyDOS_wifi_VER = "1.47" import os import time @@ -214,6 +214,10 @@ def get(self,text_url,headers=None,getJSON=False): return self.response + def post(self,text_url,data): + self.response = self._requests.post(text_url,data=data) + return self.response + def json(self): retVal = None if implementation.name.upper() == 'CIRCUITPYTHON': diff --git a/pye_gen.py b/pye_pydos.py similarity index 60% rename from pye_gen.py rename to pye_pydos.py index e012f60..1705581 100644 --- a/pye_gen.py +++ b/pye_pydos.py @@ -6,6 +6,11 @@ except: import sys +try: + from pydos_ui import Pydos_ui +except: + Pydos_ui = False + class IO_DEVICE: def __init__(self): try: @@ -22,10 +27,13 @@ def wr(self, s): sys.stdout.write(s) def rd(self): - return sys.stdin.read(1) + if Pydos_ui: + return Pydos_ui.read_keyboard(1) + else: + return sys.stdin.read(1) def rd_raw(self): - return self.rd_raw_fct(1) + return self.rd(1) def deinit_tty(self): try: @@ -35,13 +43,16 @@ def deinit_tty(self): pass def get_screen_size(self): - self.wr('\x1b[999;999H\x1b[6n') - pos = '' - char = self.rd() ## expect ESC[yyy;xxxR - while char != 'R': - pos += char - char = self.rd() - return [int(i, 10) for i in pos.lstrip("\n\x1b[").split(';')] + if Pydos_ui: + return [i for i in Pydos_ui.get_screensize()] + else: + self.wr('\x1b[999;999H\x1b[6n') + pos = '' + char = self.rd() ## expect ESC[yyy;xxxR + while char != 'R': + pos += char + char = self.rd() + return [int(i, 10) for i in pos.lstrip("\n\x1b[").split(';')] ## test, if the Editor class is already present if "pye_edit" not in globals().keys(): diff --git a/wifi_finance.py b/wifi_finance.py index e9b46f2..1e49cdd 100644 --- a/wifi_finance.py +++ b/wifi_finance.py @@ -4,6 +4,7 @@ from sys import implementation from os import uname from pydos_wifi import Pydos_wifi +import time def wifi_finance(symbol): try: @@ -12,11 +13,12 @@ def wifi_finance(symbol): _scrWidth = 80 if not symbol: - symbol = "IXIC" + symbol = ".IXIC:INDEXNASDAQ" else: symbol = symbol.upper() - prt_sym = symbol - srch_sym = symbol + prt_sym = symbol[:symbol.find(':')] + srch_sym = symbol[:symbol.find(':')] + search_attempts = 5000 # Get wifi details and more from a .env file if Pydos_wifi.getenv('CIRCUITPY_WIFI_SSID') is None: @@ -24,8 +26,16 @@ def wifi_finance(symbol): print("Connecting to %s" % Pydos_wifi.getenv('CIRCUITPY_WIFI_SSID')) - if not Pydos_wifi.connect(Pydos_wifi.getenv('CIRCUITPY_WIFI_SSID'), Pydos_wifi.getenv('CIRCUITPY_WIFI_PASSWORD')): - raise Exception("Unable to connect to WiFi!") + res = False + for i in range(2): + try: + res = Pydos_wifi.connect(Pydos_wifi.getenv('CIRCUITPY_WIFI_SSID'), Pydos_wifi.getenv('CIRCUITPY_WIFI_PASSWORD')) + break + except: + print('Retrying....') + if not res: + if not Pydos_wifi.connect(Pydos_wifi.getenv('CIRCUITPY_WIFI_SSID'), Pydos_wifi.getenv('CIRCUITPY_WIFI_PASSWORD')): + raise Exception("Unable to connect to WiFi!") print("My IP address is", Pydos_wifi.ipaddress) @@ -36,16 +46,24 @@ def wifi_finance(symbol): #search_string = 'data-symbol="^IXIC" data-field="regularMarketChangePercent"' #TEXT_URL = "https://www.moneycontrol.com/us-markets" #search_string = 'Nasdaq' + #TEXT_URL = f"https://www.google.com/search?q={symbol.replace('&','%26')}+stock+price" + #search_string = symbol + #Id_Symbol = True + #price_ident = '%)' + #window_depth=4 - TEXT_URL = f"https://www.google.com/search?q={symbol.replace('&','%26')}+stock+price" + TEXT_URL = f"https://www.google.com/finance/quote/%7Bsymbol.replace('&','%26')}" search_string = symbol + Id_Symbol = False + price_ident = 'data-last-price' + window_depth = 5 #headers = {"user-agent": "RetiredWizard@"+implementation.name.lower()+uname()[2]} print("Fetching text from %s" % TEXT_URL) response = Pydos_wifi.get(TEXT_URL) response_window = [] - for _ in range(4): + for _ in range(window_depth): response_window.append(Pydos_wifi.next(256)) if len(response_window[-1]) != 256: break @@ -61,58 +79,65 @@ def wifi_finance(symbol): print(pline) print("-" * _scrWidth) - print("Identifying symbol",end="") - name_loc = -1 iKount = 0 - while name_loc == -1 and iKount<800: - iKount +=1 - if iKount % 10 == 0: - print(".",end="") - - found_window = str(b''.join(response_window)) - - name_loc = found_window.find(' Inc. is') - if name_loc == -1: - name_loc = found_window.find(' Inc., commonly') - if name_loc == -1: - name_loc = found_window.find(' is a stock market ') - if name_loc != -1: - if found_window[:name_loc].rfind('or simply the ') != -1: - srch_sym = found_window[found_window[:name_loc].rfind('or simply the ')+14:name_loc] - elif found_window[:name_loc].rfind('>') != -1: - srch_sym = found_window[found_window[:name_loc].rfind('>')+1:name_loc] - srch_sym = srch_sym.replace(',','') - prt_sym = srch_sym.replace('&','&') - prt_sym = prt_sym.replace('amp;','') - if srch_sym[0:4].upper() == 'THE ': - srch_sym = srch_sym[4:] - print(f'* {search_string} * {srch_sym} * {prt_sym}',end="") - - if iKount<800: - for i in range(3): - response_window[i] = response_window[i+1] - try: - response_window[3] = Pydos_wifi.next(256) - if len(response_window[3]) != 256: - print('X',end="") - iKount=800 - except: - iKount=800 - print() - - print("Locating price data",end="") - response.close() - response = Pydos_wifi.get(TEXT_URL) - response_window = [] - iKount = 0 - for _ in range(4): - response_window.append(Pydos_wifi.next(256)) - if len(response_window[-1]) != 256: - iKount = 799 - break + if Id_Symbol: + print("Identifying symbol",end="") + name_loc = -1 + while name_loc == -1 and iKount') != -1: + srch_sym = found_window[found_window[:name_loc].rfind('>')+1:name_loc] + srch_sym = srch_sym.replace(',','') + prt_sym = srch_sym.replace('&','&') + prt_sym = prt_sym.replace('amp;','') + if srch_sym[0:4].upper() == 'THE ': + srch_sym = srch_sym[4:] + print(f'* {search_string} * {srch_sym} * {prt_sym}',end="") + + if iKount')+1 - pctend = pct + found_window[pct:].find('<') - #print("Debug: %s\n" % found_window[nasdaq:pctend]) - pricest = found_window[:pctst-2].rfind('>')+1 - priceend = pricest + found_window[pricest:].find('<') - if nasdaq != -1: - print(f'{prt_sym}: {found_window[pricest:priceend]} {found_window[pctst:pctend].replace("<","")}\n') +# Final scrape logic +# Google Search +# pct = found_window.find(price_ident) +# pctst = found_window[:pct].rfind('>')+1 +# pctend = pct + found_window[pct:].find('<') +# print("Debug: %s\n" % found_window[nasdaq:pctend]) +# pricest = found_window[:pctst-2].rfind('>')+1 +# priceend = pricest + found_window[pricest:].find('<') + +# Google finance + pricest = found_window.find(price_ident)+len(price_ident)+2 + priceend = pricest + found_window[pricest:].find('"') + pctst = -1 + + #print(f'Debug: start loc: {pricest} end loc: {priceend}\n{found_window[nasdaq:]}') + + print(f'{prt_sym}: {found_window[pricest:priceend]}',end="") + if pctst != -1: + print(f' {found_window[pctst:pctend].replace("<","")}\n') + else: + print('\n') else: print(f"{prt_sym} symbol not found\n") @@ -172,8 +210,23 @@ def wifi_finance(symbol): del response_window del found_window +print('\nDemonstration Web "scraping" program. The web sites being used in the') +print('demonstration will often change and break the algorithm used to locate a') +print('stock price. When that happens this program needs to be updated to work') +print('with the new web site or find a new one.\n') +print('The current web site being used is: https://www.google.com/finance\n') +print('With this site the symbol passed to wifi_finance must be formatted as') +print('follows: symbol:exchange. So for Apple Inc, you would enter AAPL:NASDAQ') +print('or for AT&T enter T:NYSE. To retrieve the price of an index format the') +print('symbol as follows: .indexsymbol:INDEXsymbol. For example Nasdaq:') +print('.IXIC:INDEXNASDAQ, Dow Jones: .DJI:INDEXDJX, S&P 500: .INX:INDEXSP. The') +print('index symbols can be retrieved by going to the www.google.com/finance page') +print("and selecting the index you're inerested in. The formatted symbol will be") +print('updated at the end of the URL (not the symbol displayed in the search box.') + if __name__ == "PyDOS": wifi_finance(passedIn) else: print('Enter "wifi_finance.wifi_finance("symbol")" in the REPL or PEXEC command to run.') - print(' A null symbol ("") will default to the Nasdaq Index') \ No newline at end of file + print(' A null symbol ("") will default to the Nasdaq Index') +