diff --git a/tools/templates/templates.py b/tools/templates/templates.py index c1d696cbc..d58e57f39 100644 --- a/tools/templates/templates.py +++ b/tools/templates/templates.py @@ -30,36 +30,316 @@ Usage: """ +import sys import io -import pycurl -import certifi +import requests from io import BytesIO from io import StringIO from datetime import datetime +import json -column = 27 # Start position of {"NAME":... in line + +LIST_URL = "https://templates.blakadder.com/list.json" +TEMPLATES = "../../TEMPLATES.md" + +COLUMN = 27 # Start position of {"NAME":... in line + +# Some values from support.ino and tasmota_templates.h +AGPIO = lambda x : x << 5 +GPIO_NONE = 0 +GPIO_USER = AGPIO(GPIO_NONE)+1 +GPIO_ADC_INPUT = 147 +GPIO_ADC_JOY = 104 + +# Conversion table extracted from Tasmota code +GPIO_CONVERT = [ + 0x0000, + 0x04A0, + 0x04C0, + 0x04E0, + 0x0520, + 0x0260, + 0x0280, + 0x0560, + 0x0420, + 0x00A0, + 0x00A1, + 0x00A2, + 0x00A3, + 0x00A4, + 0x00A5, + 0x00A6, + 0x00A7, + 0x0020, + 0x0021, + 0x0022, + 0x0023, + 0x00E0, + 0x00E1, + 0x00E2, + 0x00E3, + 0x00E4, + 0x00E5, + 0x00E6, + 0x00E7, + 0x0100, + 0x0101, + 0x0102, + 0x0103, + 0x0104, + 0x0105, + 0x0106, + 0x0107, + 0x01A0, + 0x01A1, + 0x01A2, + 0x01A3, + 0x01A4, + 0x0160, + 0x0161, + 0x0162, + 0x0163, + 0x01C0, + 0x01C1, + 0x01C2, + 0x01C3, + 0x01C4, + 0x0440, + 0x0120, + 0x0121, + 0x0122, + 0x0123, + 0x0140, + 0x0141, + 0x0142, + 0x0143, + 0x0580, + 0x05A0, + 0x05C0, + 0x05E0, + 0x0640, + 0x0660, + 0x0300, + 0x0320, + 0x03E0, + 0x06A0, + 0x06E0, + 0x0700, + 0x0720, + 0x0740, + 0x0760, + 0x0780, + 0x07A0, + 0x07C0, + 0x07E0, + 0x0800, + 0x0820, + 0x0840, + 0x00C0, + 0x00C1, + 0x00C2, + 0x00C3, + 0x00C4, + 0x00C5, + 0x00C6, + 0x00C7, + 0x0040, + 0x0041, + 0x0042, + 0x0043, + 0x0180, + 0x0181, + 0x0182, + 0x0183, + 0x0600, + 0x0620, + 0x0860, + 0x06C0, + 0x0880, + 0x08A0, + 0x08C0, + 0x0460, + 0x0480, + 0x08E0, + 0x0900, + 0x0920, + 0x0940, + 0x0340, + 0x0360, + 0x0380, + 0x03A0, + 0x03C0, + 0x0960, + 0x0980, + 0x09A0, + 0x09C0, + 0x09E0, + 0x0A00, + 0x0060, + 0x0061, + 0x0062, + 0x0063, + 0x0080, + 0x0081, + 0x0082, + 0x0083, + 0x0A20, + 0x0A40, + 0x0A60, + 0x0A80, + 0x0AA0, + 0x0AC0, + 0x0AE0, + 0x0B00, + 0x0B20, + 0x0B40, + 0x0B60, + 0x0B80, + 0x0BA0, + 0x0BC0, + 0x0BE0, + 0x0C00, + 0x0C20, + 0x0C40, + 0x0C80, + 0x0CA0, + 0x0CC0, + 0x0CE0, + 0x0CC1, + 0x0CE1, + 0x0D40, + 0x0D60, + 0x0D80, + 0x0220, + 0x0240, + 0x0C60, + 0x01E0, + 0x0200, + 0x0400, + 0x0DA0, + 0x0DC0, + 0x0DE0, + 0x0E00, + 0x0E20, + 0x0E40, + 0x0E60, + 0x0E80, + 0x0EA0, + 0x0EC0, + 0x0EE0, + 0x0EE1, + 0x0EE2, + 0x0F40, + 0x0F60, + 0x0F80, + 0x0FA0, + 0x0FC0, + 0x0FE0, + 0x1000, + 0x1020, + 0x1040, + 0x1060, + 0x1080, + 0x10A0, + 0x10C0, + 0x10E0, + 0x1100, + 0x1120, + 0x0540, + 0x0500, + 0x1140, + 0x1160, + 0x1180, + 0x11A0, + 0x11C0, + 0x11E0, + 0x1200, + 0x1220, + 0x1240, + 0x0680, + 0x1340, + 0x1360, + 0x1380, + 0x13C0, + 0x13E0, + 0x1400, + 0x1420, + 0x1440, + 0x1460, + 0x1480, + 0x14A0, + 0x14C0, + 0x14E0 +] + + +def is_old_template(template): + """find out it the template is old format""" + # Old format <=> 13 gpios AND all gpios <= 255 + if "GPIO" in template and len(template["GPIO"]) == 13: + for g in template["GPIO"]: + if g > 255: + return False + return True + return False + +def gpio_convert(gpio): + """Conversion as per https://tasmota.github.io/docs/Components/#gpio-conversion""" + if gpio >= len(GPIO_CONVERT): + return GPIO_USER + return GPIO_CONVERT[gpio] + +def adc0_convert(adc0): + """Conversion as per https://tasmota.github.io/docs/Components/#adc-conversion""" + adc0 = adc0 & 0x0F + if 0 == adc0: + return GPIO_NONE + elif 8 == adc0: + return AGPIO(GPIO_ADC_JOY); # Joystick + elif adc0 > 7: + return GPIO_USER + return AGPIO(GPIO_ADC_INPUT + adc0 -1) + +def convert_gpios(gpios, flag): + new_gpios = [] + for g in gpios: + new_gpios.append(gpio_convert(g)) + new_gpios.append(adc0_convert(flag)) + return new_gpios + +def convert_template(template): + if not is_old_template(template): + return template + return { "NAME": template["NAME"], + "GPIO": convert_gpios(template["GPIO"], template["FLAG"]), + "FLAG":0, + "BASE": template["BASE"] } + +def get_templates_list(): + """Download templates list from template website""" + response = requests.get(LIST_URL) + if response.status_code != 200: + printf(f"Error GET({URL}) returned code {response.status_code}\n") + exit() + return response.text.split('\n') def main(): print ("\n*** templates.py v20200514 by Theo Arends ***") - # Download from template website - buffer = BytesIO() - url = "https://templates.blakadder.com/list.json" - c = pycurl.Curl() - c.setopt(c.URL, url) - c.setopt(c.WRITEDATA, buffer) - c.setopt(c.CAINFO, certifi.where()) - c.perform() - c.close() - body = buffer.getvalue() - fin = StringIO(body.decode('UTF-8')) - now = datetime.now() month = now.strftime('%B') year = now.strftime('%Y') + # if stdin is a file, read the file instead of downloading (usefull for testing) + if sys.__stdin__.isatty(): + print(f"Get template list from {LIST_URL}\n") + template_list = get_templates_list() + else: + print("Get template list from stdin\n") + template_list = sys.__stdin__.readlines() + # Write to root/TEMPLATES.md - fout = open("..\..\TEMPLATES.md","w+") + fout = open(TEMPLATES,"w+") fout.write("\"Logo\"\n") fout.write("\n") @@ -67,32 +347,32 @@ def main(): fout.write("\n") fout.write("Find below the available templates as of " + month + " " + year + ". More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)\n") - not_first = 0 - fline = fin.readlines() - for line in fline: + first = True + for line in template_list: if line.strip(): if line.startswith("##"): - if not_first: + if not first: fout.write('```\n') fout.write('\n') - fout.write(line) + fout.write(line+'\n') fout.write('```\n') - not_first = 1 + first = False elif line.startswith("#"): - noop = 0 + pass else: - pos1 = line.find("{") - if pos1 < column: - a = column + 2 - pos1 - lout = line[0:pos1 - 4] + " "*a + line[pos1:len(line)] - else: - lout = line[0:pos1 - 4] + " " + line[pos1:len(line)] - fout.write(lout) + json_start = line.find("{") + name = line[:json_start].strip() + try: + template = json.loads(line[json_start:]) + template = convert_template(template) + except json.decoder.JSONDecodeError as ex: + template = "Not available" + + fout.write(f"{name:<{COLUMN}} {json.dumps(template)}\n") fout.write('```\n') fout.close() - fin.close() if __name__ == "__main__": main()