Put ESP Screens in English and keep layouts when entity IDs change (0.2.40)
Everything a user sees or reads is now English: both boards' labels, status replies and logs, the ESP Screens editor and Alerts cheatsheet, and the README and guides (docs/TILES.md, CALIBRATING.md, ACCEPTANCE.md and TROUBLESHOOTING.md replace the Dutch file names). Labels follow Home Assistant's own English names (Heat/Cool modes, Heating/Cooling actions, Away, Returning to dock, weather conditions), dates use English abbreviations and the top bar writes numbers the English way. Docs use HA 2026.9's menu names (Settings -> Apps, App store, Settings -> Tools). Unused legacy files (home-like.yaml, buttons.yaml, a.out) are removed. Firmware 0.2.34 names its entities in English. Home Assistant registers a renamed ESPHome entity under a new entity ID, so the inbox text.<screen>_tegelinstellingen becomes text.<screen>_tile_settings and the layout stored under the old ID would be lost. The manager now recognises the screen by its device, during a run or after a restart, and moves its layout and update history along; the Update button and the nightly round follow the screen through the rename. Screens that still run 0.2.33 or older keep working: both languages are matched. Main is the only release branch from now on. Tested on a Home Assistant Yellow (HA 2026.9.1) with both bench boards: see docs/TEST_RESULTS_0240.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+17
-17
@@ -8,8 +8,8 @@ import statistics
|
||||
import time
|
||||
from calibrate import write_file
|
||||
|
||||
TARGETS = [('linksboven', (24, 24)), ('rechtsboven', (455, 24)),
|
||||
('rechtsonder', (455, 455)), ('linksonder', (24, 455)), ('midden', (240, 240))]
|
||||
TARGETS = [('top-left', (24, 24)), ('top-right', (455, 24)),
|
||||
('bottom-right', (455, 455)), ('bottom-left', (24, 455)), ('center', (240, 240))]
|
||||
PATTERN = re.compile(r'GT911 press x=(\d+) y=(\d+) test=([01])')
|
||||
|
||||
|
||||
@@ -18,35 +18,35 @@ def screen_point(x, y, rotation=0):
|
||||
if rotation == 90: return y, 479-x
|
||||
if rotation == 180: return 479-x, 479-y
|
||||
if rotation == 270: return 479-y, x
|
||||
raise ValueError('Rotatie moet 0, 90, 180 of 270 zijn.')
|
||||
raise ValueError('Rotation must be 0, 90, 180, or 270.')
|
||||
|
||||
|
||||
def verify(data):
|
||||
if data.get('screen') != [480,480] or len(data.get('points',[])) != 5:
|
||||
raise ValueError('Verwacht vijf meetpunten op een 480x480 GT911-scherm.')
|
||||
raise ValueError('Expected five measurement points on a 480x480 GT911 screen.')
|
||||
result=[]
|
||||
for p,(name,target) in zip(data['points'],TARGETS):
|
||||
if p.get('name') != name or len(p.get('samples',[])) != 3:
|
||||
raise ValueError('Volg de vijf doelen; ieder doel vereist drie aparte tikken.')
|
||||
raise ValueError('Follow the five targets; each target requires three separate taps.')
|
||||
samples=[]
|
||||
for xy in p['samples']:
|
||||
if len(xy)!=2 or any(type(v) is not int or not 0<=v<480 for v in xy):
|
||||
raise ValueError('Touchcoördinaten vallen buiten 480x480.')
|
||||
raise ValueError('Touch coordinates fall outside 480x480.')
|
||||
samples.append(screen_point(*xy, data.get('rotation',0)))
|
||||
center=tuple(statistics.median(x[i] for x in samples) for i in (0,1))
|
||||
error=math.dist(center,target)
|
||||
spread=max(math.dist(x,center) for x in samples)
|
||||
result.append(dict(name=name,error_px=round(error,1),spread_px=round(spread,1)))
|
||||
if error>16 or spread>18:
|
||||
raise ValueError(f'{name}: fout {error:.1f}px / spreiding {spread:.1f}px. Controleer rotatie en GT911-transform; geen ADC-fit gebruiken.')
|
||||
raise ValueError(f'{name}: error {error:.1f}px / spread {spread:.1f}px. Check rotation and the GT911 transform; do not use an ADC fit.')
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--port', help='USB-poort; firmware moet het GT911-meetscherm tonen')
|
||||
parser.add_argument('--port', help='USB port; firmware must show the GT911 measurement screen')
|
||||
parser.add_argument('--output',type=Path,default=Path('measurements-guition.json'))
|
||||
parser.add_argument('--input',type=Path,help='Controleer een bestaand meetbestand zonder USB')
|
||||
parser.add_argument('--input',type=Path,help='Check an existing measurement file without USB')
|
||||
parser.add_argument('--rotation',type=int,choices=(0,90,180,270),default=0)
|
||||
args=parser.parse_args()
|
||||
try:
|
||||
@@ -54,30 +54,30 @@ def main():
|
||||
data=json.loads(args.input.read_text())
|
||||
else:
|
||||
import serial
|
||||
if not args.port: raise ValueError('--port is nodig voor een fysieke meting.')
|
||||
if args.output.exists(): raise ValueError('Meetbestand bestaat al; kies een andere naam.')
|
||||
if not args.port: raise ValueError('--port is required for a physical measurement.')
|
||||
if args.output.exists(): raise ValueError('Measurement file already exists; choose a different name.')
|
||||
data=dict(screen=[480,480],rotation=args.rotation,points=[])
|
||||
with serial.Serial(args.port,115200,timeout=.2) as port:
|
||||
for name,xy in TARGETS:
|
||||
input(f'{name} {xy}: druk Enter en tik daarna drie keer alleen dit kruisje, met loslaten ertussen. ')
|
||||
input(f'{name} {xy}: press Enter, then tap only this crosshair three times, releasing in between. ')
|
||||
port.reset_input_buffer()
|
||||
samples=[]; deadline=time.monotonic()+90; last=0
|
||||
while len(samples)<3 and time.monotonic()<deadline:
|
||||
m=PATTERN.search(port.readline().decode(errors='replace'))
|
||||
if not m: continue
|
||||
if m[3]!='1': raise ValueError('Het geïsoleerde GT911-meetscherm is niet actief.')
|
||||
if m[3]!='1': raise ValueError('The isolated GT911 measurement screen is not active.')
|
||||
if time.monotonic()-last < .4:continue
|
||||
samples.append([int(m[1]),int(m[2])]);last=time.monotonic()
|
||||
print(f' {len(samples)}/3',flush=True)
|
||||
if len(samples)!=3:raise ValueError(f'{name}: onvoldoende tikken ontvangen.')
|
||||
if len(samples)!=3:raise ValueError(f'{name}: not enough taps received.')
|
||||
data['points'].append(dict(name=name,samples=samples))
|
||||
write_file(args.output,json.dumps(data,indent=2)+'\n')
|
||||
for row in verify(data):print(row)
|
||||
print('PASS: alle vijf GT911-doelen geverifieerd; geen HA-acties uitgevoerd.')
|
||||
print('PASS: all five GT911 targets verified; no HA actions performed.')
|
||||
except (ValueError,OSError,TypeError,KeyError,EOFError) as exc:
|
||||
parser.exit(1,f'Fout: {exc}\n')
|
||||
parser.exit(1,f'Error: {exc}\n')
|
||||
except KeyboardInterrupt:
|
||||
parser.exit(130,'Meting afgebroken.\n')
|
||||
parser.exit(130,'Measurement aborted.\n')
|
||||
|
||||
|
||||
if __name__=='__main__': main()
|
||||
|
||||
Reference in New Issue
Block a user