Skip to main content

Connect to a Tesy Boiler without the use of the modeco cloud.

Project description

TesyLocal

The opposite of Tesy cloud

Intro

This little package only reads data from your tesy boiler at the moment.

Requirements:

  • Python3.6 and up
  • Boiler firmware of 20.20 and up

Index

  1. Get Started
  2. Arguments
  3. Boiler Modes
  4. Home assistant YAML
  5. Notes

Simple how-to get started / command examples

# This is a small app, using the TesyLocal module
from tesylocal import tesy
# Please specify your boiler IP like so, and if you want a initial sync of all values
## NOTE: This is only important if you are not planning to integrate this.
boiler = tesy("192.168.1.1", "sync")
# No sync:
boiler = tesy("192.168.1.1", "nosync")
# Then print a property, This requires "sync" or updateallvalues / updateschedules after connecting.
print(boiler.tesyprettyprinter)

## Other options:
# Update values:
boiler.updateallvalues('192.168.2.254')
boiler.updateschedules('192.168.2.254')
# Got DHCP?, Or perhaps you want to validate the IP once in a while or check if the device is alive:
boiler.check_ip_status('192.168.2.254')
# Turn on the boiler
boiler.boileronoff("192.168.2.254","on")
# Turn the boiler off
boiler.boileronoff("192.168.2.254","off")
# More are available:
# boostonoff, boilermanualmode, boileronoff, manualtemp,
# automanualmode, boilermode, resetpower, settime, setboilervolume, setvacationmode

Available commands and expected arguments

Command Ip Needed Argument 1 Argument 2 Argument 3 Notes
boiler.updateallvalues True N/A N/A N/A Updates all current values for pretty print
boiler.updateschedules True N/A N/A N/A Updates all schedules for pretty print
boiler.check_ip_status True N/A N/A N/A Validates if the IP accepts /devstat and if the JSON we get is valid.
boiler.boileronoff True "on" / "off" N/A N/A Turns the boiler on or off, must be string
boiler.boostonoff True 0 - 1 N/A N/A Turns boost mode on or off, must be int 0 to 1 (0 off, 1 on)
boiler.manualtemp True 14 - 75 N/A N/A Sets the temperature of the boiler if the boiler is in manual mode, Must be int 14 to 75
boiler.automanualmode True 14 - 75 N/A N/A Sets the temperature of manual mode, but also forces the boiler in manual mode regardless, Must be int 14 to 75
boiler.boilermode True 0 - 9 N/A N/A Sets a mode of the boiler see "Boiler modes" chapter, Must be int 0 to 9
boiler.resetpower True N/A N/A N/A Resets the kWh meter of the boiler, Note this not the since powered on kWh counter, but a second meter
boiler.settime True Europe/Amsterdam N/A N/A Sets the time of the boiler to now, must need time zone in "Europe/Amsterdam" format
boiler.setboilervolume True 100 N/A N/A Sets the volume of the boiler, This might be wrong from factory and is a bug in FW21.21 that it cannot update, must be int one off (50, 80, 100, 120, 150)
boiler.setvacationmode True 23/12/32 (Y/M/D) 00 - 23 14 -75 Turns on vacation mode, needs date as string, hour as string, temp as int (boiler.setvacationmode("ip", "23/12/31","13",75)
boiler.pretyprinter False N/A N/A N/A Shows a pretty format of all the values (needs, sync or updateallvalues/updateschedules)
boiler.tesyprinter False N/A N/A N/A Raw data output (needs, sync or updateallvalues/updateschedules)
boiler.tesyprinter1 False N/A N/A N/A Raw data output of schedule 1 (needs, sync or updateschedules)
boiler.tesyprinter2 False N/A N/A N/A Raw data output of schedule 2 (needs, sync or updateschedules)
boiler.tesyprinter3 False N/A N/A N/A Raw data output of schedule 3 (needs, sync or updateschedules)

This is a example of the output you can expect with the print(boiler.tesyprettyprinter)

==========================================
# General:                               #
==========================================
| Temp:  53.0 | Target:  50  |
| Next Temp: 50 at 14:00
| Boost:  0   | Power:  on   | State:  READY
| Errors:  0   | Liters: 100 |
| TimeZone: CEST
| Local Time: 2022-04-08 13:27
==========================================
# Power Usage:                           #
==========================================
| Alltime KWH: 0.80
| Current KWH: 0.06
| Max Power: 2400
| Counter Reset: 2022-04-08 10:55:45
==========================================
# MyTesy:                                #
==========================================
| MyTDesc:           boiler1
| MyTEmail: noreply@yourdomain.com
| MyTDetail:
==========================================
# Vacation:                              #
==========================================
| Vacation Set:  0
| Vacation Target Temp:  70
| Vacation date (Y:M:D:H): 21:12:1:20
| Vacation WeekDay: 3
==========================================
# Wifi: (outgoing)                       #
==========================================
| Errors:  0
| Conected:  1
| Signal: -41
| SSID:       SSSIDDDD
| Internet:              1
==========================================
# Wifi: (Indoor)                         #
==========================================
| Protection:             psk2
| Password:               Password
==========================================
# Misc:                                  #
==========================================
| DevID:  2004-3402 FW21.21
| MacAddr:      70:f1:

Boiler modes:

1: Manual mode
2: Weekly program 1
3: Weekly program 2
4: Weekly program 3
5: Eco 1
6: Eco 2
7: Eco 3
8: ?
9: Vacation

Note that there are a total of 9 modes, Not sure what they all do.

Home Assistant

Currently a integration is in the works, but until then you can add the following to your configuration.yaml

Note that the ?_=1634912123253 (epoch) is a identifier to track your request, it is not needed to control the boiler.

rest_command:
  tsmt:
    url: "http://192.168.2.254/setTemp?val={{ temperature }}"
    method: GET

automation:
  - alias: "Tesy Temperature input automatically changed"
    trigger:
      platform: state
      entity_id: sensor.tesyboilertargettemp
    action:
      service: input_number.set_value
      target:
        entity_id: input_number.tesyboilermanualtempinput
      data:
        value: "{{ trigger.to_state.state }}"
  - alias: "Tesy Temperature input manually changed"
    trigger:
      platform: state
      entity_id: input_number.tesyboilermanualtempinput
    action:
      service: rest_command.tsmt
      data:
        temperature: "{{ trigger.to_state.state }}"

input_number:
  tesyboilermanualtempinput:
    name: Set Tesy Manual Temp
    min: 14
    max: 75
    step: 1
    unit_of_measurement: "°C"
    icon: mdi:temperature-celsius

switch:
  - platform: command_line
    switches:
      tesyboostonoff:
        command_on: "/usr/bin/curl -X GET http://192.168.2.254/boostSW?mode=1"
        command_off: "/usr/bin/curl -X GET http://192.168.2.254/boostSW?mode=0"
        command_state: "/usr/bin/curl -sX GET http://192.168.2.254/status"
        value_template: "{{ value_json['boost'] == '1' }}"
        friendly_name: Boost Tesy!
        icon_template: >
          {% if value_json['boost'] == '0' %} mdi:rocket
          {% elif value_json['boost'] == '1' %} mdi:rocket-launch
          {% else %} mdi:help-circle
          {% endif %}
      tesyonoff:
        command_on: "/usr/bin/curl -X GET http://192.168.2.254/power?val=on"
        command_off: "/usr/bin/curl -X GET http://192.168.2.254/power?val=off"
        command_state: "/usr/bin/curl -sX GET http://192.168.2.254/status"
        value_template: "{{ value_json['power_sw'] == 'on' }}"
        friendly_name: Tesy power switch!
        icon_template: >
          {% if value_json['power_sw'] == "on" %} mdi:toggle-switch
          {% else %} mdi:toggle-switch-off
          {% endif %}
      tesyresetpower:
        command_on: "/usr/bin/curl -X GET http://192.168.2.254/resetPow"
        friendly_name: Tesy power Reset!
      tesysetsetmanualmode:
        command_on: "/usr/bin/curl -X GET http://192.168.2.254/modeSW?mode=1"
        # Set a default schedule here if you dont want manual mode any longer
        command_off: "/usr/bin/curl -X GET http://192.168.2.254/modeSW?mode=2"
        command_state: "/usr/bin/curl -sX GET http://192.168.2.254/status"
        value_template: "{{ value_json['mode'] == '1' }}"
        friendly_name: Set Tesy manual mode
        icon_template: >
          {% if value_json['mode'] == '1' %} mdi:water-boiler
          {% elif value_json['mode'] == '2' %} mdi:calendar
          {% elif value_json['mode'] == '3' %} mdi:calendar
          {% elif value_json['mode'] == '4' %} mdi:calendar
          {% elif value_json['mode'] == '5' %} mdi:sprout
          {% elif value_json['mode'] == '6' %} mdi:sprout
          {% elif value_json['mode'] == '7' %} mdi:sprout
          # No idea what mode 8 is.
          {% elif value_json['mode'] == '8' %} mdi:help
          {% elif value_json['mode'] == '9' %} mdi:beach
          {% else %} mdi:help-circle
          {% endif %}
sensor:
  - platform: rest
    resource: http://192.168.2.254/status
    name: tesyboiler
    method: GET
    value_template: "OK"
    json_attributes:
      - gradus
      - ref_gradus
      - heater_state
      - err_flag
      - boost
      - power_sw
      - volume
      - watts
      - mode
  - platform: rest
    resource: http://192.168.2.254/calcRes
    name: tesyboilerpower
    method: GET
    value_template: "OK"
    json_attributes:
      - kwh
      - ltc
      - resetDate

template:
  - sensor:
      - name: "Boiler kWh all time"
        unit_of_measurement: "kWh"
        device_class: energy
        state_class: total_increasing
        state: "{{ states('sensor.TesyBoilerKwhAllTime') }}"
  - sensor:
      - name: "tesyboilerkwhresetdate"
        icon: mdi:calendar-blank-outline
        unique_id: "TesyBoilerKwhResetDate"
        state: "{{ state_attr('sensor.tesyboilerpower', 'resetDate') }}"
  - sensor:
      - name: "tesyboilerkwhafterreset"
        icon: mdi:lightning-bolt
        unique_id: "TesyBoilerKwhAfterReset"
        state: "{{ state_attr('sensor.tesyboilerpower', 'kwh') }}"
        unit_of_measurement: "kWh"
        device_class: energy
  - sensor:
      - name: "tesyboilerwatervolume"
        icon: mdi:cup-water
        unique_id: "TesyBoilerWaterVolume"
        state: "{{ state_attr('sensor.tesyboiler', 'volume') }}"
        unit_of_measurement: "L"
  - sensor:
      - name: "tesyboilerwatts"
        icon: mdi:power-plug
        unique_id: "TesyBoilerWatts"
        state: "{{ state_attr('sensor.tesyboiler', 'watts') }}"
        unit_of_measurement: "W"
  - sensor:
      - name: "tesyboilermode"
        icon: mdi:calendar
        unique_id: "TesyBoilerMode"
        state: "{{ state_attr('sensor.tesyboiler', 'mode') }}"
  - sensor:
      - name: "tesyboilererror"
        icon: mdi:water-boiler-alert
        unique_id: "TesyBoilerError"
        state: "{{ state_attr('sensor.tesyboiler', 'err_flag') }}"
  - sensor:
      - name: "tesyboilerboost"
        icon: mdi:arrow-up-circle
        unique_id: "TesyBoilerBoost"
        state: "{{ state_attr('sensor.tesyboiler', 'boost') }}"
  - sensor:
      - name: "tesyboileronoff"
        icon: mdi:help-circle
        unique_id: "TesyBoilerOnOff"
        state: "{{ state_attr('sensor.tesyboiler', 'power_sw') }}"
  - sensor:
      - name: "tesyboilerstate"
        icon: mdi:help-circle
        unique_id: "TesyBoilerState"
        state: "{{ state_attr('sensor.tesyboiler', 'heater_state') }}"
  - sensor:
      - name: "tesyboilertargettemp"
        icon: mdi:help-circle
        unique_id: "TesyBoilerTargetTemp"
        state: "{{ state_attr('sensor.tesyboiler', 'ref_gradus') }}"
  - sensor:
      - name: "tesyboilerwatertemp"
        icon: mdi:temperature-celsius
        unique_id: "TesyBoilerWaterTemp"
        state: "{{ state_attr('sensor.tesyboiler', 'gradus') }}"
        unit_of_measurement: "°C"
  - sensor:
      - name: "tesyboilerwatertargettemp"
        icon: mdi:temperature-celsius
        unique_id: "TesyBoilerWaterTargetTemp"
        state: "{{ state_attr('sensor.tesyboiler', 'ref_gradus') }}"
        unit_of_measurement: "°C"
  - sensor:
      - name: "tesyboilerkwhalltime"
        icon: mdi:lightning-bolt
        unique_id: "TesyBoilerKwhAllTime"
        state: "{{ state_attr('sensor.tesyboilerpower', 'ltc') }}"
        unit_of_measurement: "kWh"
        device_class: energy

Notes:

Here are some of the URLs you can manually make to control the boiler and a description:

1634911445424 == epoch

# boost on
http://192.168.2.254/boostSW?mode=0&_=1634911445424
# boost off
http://192.168.2.254/boostSW?mode=1&_=1634911446795
# set adaptive:
http://192.168.2.254/adaptive?val=
# Set antifreeze:
http://192.168.2.254/aantifrize?val=    # changeStatusParam, antifrost_enable   1 and 0
# Set lock:
http://192.168.2.254/lockKey?val=   # changeStatusParam lockB 1 and 0

# set to temp
http://192.168.2.254/setTemp?val=45&_=1634911879615
# manual mode
http://192.168.2.254/modeSW?mode=1&_=1634912123253
# set program 1
http://192.168.2.254/modeSW?mode=2&_=1634912027732
# set 2
http://192.168.2.254/modeSW?mode=3&_=1634912041121
# set 3
http://192.168.2.254/modeSW?mode=4&_=1634912071235
# eco 1
http://192.168.2.254/modeSW?mode=5&_=1634912151669
# eco 2
http://192.168.2.254/modeSW?mode=6&_=1634912164061
# eco 3
http://192.168.2.254/modeSW?mode=7&_=1634912180802
# device status
http://192.168.2.254/devstat?_=1634923248104
# get status
http://192.168.2.254/status?_=1634911418801
language+ set up status
http://192.168.2.254/getAccessories?_=1634923248606
# Set volume
http://192.168.2.254/setVolume?_=1634912180802&liters=100
http://192.168.2.254/setVolume&liters=100
# my tesy profile
http://192.168.2.254/mtProfile?_=1634911562552
# internet test
http://192.168.2.254/inettest?_=1634911553629
# kwh info
http://192.168.2.254/calcRes?&watt=&_=1634911625571
http://192.168.2.254/calcRes&_=1634911625571
# get volume
http://192.168.2.254/getVolume?_=1634911621820
# get schedule program 3
http://192.168.2.254/getP3?_=1634911711930
# get schedule program 2
http://192.168.2.254/getP2?_=1634911711930
# get schedule program 1
http://192.168.2.254/getP1?_=1634911711930
# get vacation
http://192.168.2.254/getVacation?_=1634911711432
# reset power
http://192.168.2.254/resetPow?_=1634912213060
# get power capacity
http://192.168.2.254/watt?_=1634912213060
# set power
http://192.168.2.254/power?val=1000&_=1634912213060

# Set vacation
# 30 december 2021 till 02:00 set to 70 This is day number 4 of the week sunday = 0 monday = 1,,
http://192.168.2.254/setVacation?_=1634990836894&vYear=21&vMonth=12&vMDay=30&vWDay=4&vHour=02&vTemp=70
# 1 december 2021 till 20:00 set to 70 This is day number 3 of the week sunday = 0 monday = 1,,
http://192.168.2.254/setVacation?_=1634990969916&vYear=21&vMonth=12&vMDay=1&vWDay=3&vHour=20&vTemp=70

# set a new item in the schedule:
http://192.168.2.254/setP1
+ body:
POST /setP1 HTTP/1.1
Host: 192.168.2.254
Connection: keep-alive
Content-Length: 1512
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Origin: http://192.168.2.254
Referer: http://192.168.2.254/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,nl;q=0.8
dnt: 1
sec-gpc: 1
&Mon00=30&Mon01=30&Mon02=30&Mon03=30&Mon04=30&Mon05=30&Mon06=30&Mon07=50&Mon08=50&Mon09=50&Mon10=40&Mon11=40&Mon12=50&Mon13=50&Mon14=40&Mon15=40&Mon16=40&Mon17=50&Mon18=50&Mon19=30&Mon20=30&Mon21=30&Mon22=30&Mon23=30&Tue00=30&Tue01=30&Tue02=30&Tue03=30&Tue04=30&Tue05=30&Tue06=30&Tue07=50&Tue08=50&Tue09=50&Tue10=40&Tue11=40&Tue12=50&Tue13=50&Tue14=40&Tue15=40&Tue16=40&Tue17=50&Tue18=50&Tue19=30&Tue20=30&Tue21=30&Tue22=30&Tue23=30&Wen00=30&Wen01=30&Wen02=30&Wen03=30&Wen04=30&Wen05=30&Wen06=30&Wen07=50&Wen08=50&Wen09=50&Wen10=40&Wen11=40&Wen12=50&Wen13=50&Wen14=40&Wen15=40&Wen16=40&Wen17=50&Wen18=50&Wen19=30&Wen20=30&Wen21=30&Wen22=30&Wen23=30&Thu00=30&Thu01=30&Thu02=30&Thu03=30&Thu04=30&Thu05=30&Thu06=30&Thu07=45&Thu08=45&Thu09=45&Thu10=45&Thu11=45&Thu12=45&Thu13=45&Thu14=45&Thu15=55&Thu16=65&Thu17=75&Thu18=75&Thu19=30&Thu20=30&Thu21=30&Thu22=30&Thu23=30&Fri00=30&Fri01=30&Fri02=30&Fri03=30&Fri04=30&Fri05=30&Fri06=30&Fri07=45&Fri08=45&Fri09=45&Fri10=35&Fri11=35&Fri12=45&Fri13=45&Fri14=35&Fri15=35&Fri16=35&Fri17=35&Fri18=45&Fri19=45&Fri20=55&Fri21=65&Fri22=75&Fri23=75&Sat00=30&Sat01=30&Sat02=30&Sat03=30&Sat04=30&Sat05=30&Sat06=30&Sat07=30&Sat08=30&Sat09=30&Sat10=50&Sat11=60&Sat12=60&Sat13=50&Sat14=50&Sat15=50&Sat16=50&Sat17=50&Sat18=50&Sat19=50&Sat20=50&Sat21=50&Sat22=50&Sat23=50&Sun00=30&Sun01=30&Sun02=30&Sun03=30&Sun04=30&Sun05=30&Sun06=30&Sun07=30&Sun08=30&Sun09=30&Sun10=50&Sun11=60&Sun12=60&Sun13=50&Sun14=50&Sun15=50&Sun16=50&Sun17=50&Sun18=50&Sun19=30&Sun20=30&Sun21=30&Sun22=30&Sun23=30

# update boiler time and date
http://192.168.2.254/setdate?tOffset=CET-1CEST,M3.5.0,M10.5.0/3&tDay=5&tMonth=10&tYear=2022&tHour=16&tMin=0&tSec=00?_=1664978401338

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tesylocal-1.4.1.tar.gz (26.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tesylocal-1.4.1-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

Details for the file tesylocal-1.4.1.tar.gz.

File metadata

  • Download URL: tesylocal-1.4.1.tar.gz
  • Upload date:
  • Size: 26.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.6

File hashes

Hashes for tesylocal-1.4.1.tar.gz
Algorithm Hash digest
SHA256 ae5ad7bc4d6327e3570a1cdab2a1e0be6c31d1ab0d55ea93bac38ac9bddc2bb1
MD5 33c7534816b67396a45268f1bfd28c47
BLAKE2b-256 73ab677a59c2eb08d64a7de674dea0e0e6d4a6d97d43edf2910d1aeaa606ee48

See more details on using hashes here.

File details

Details for the file tesylocal-1.4.1-py3-none-any.whl.

File metadata

  • Download URL: tesylocal-1.4.1-py3-none-any.whl
  • Upload date:
  • Size: 22.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.6

File hashes

Hashes for tesylocal-1.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 df62d9f9aabe26879d52cf17adf341403953372bcea09ce51d45f9ea4daf190a
MD5 e8434e73ee26a1de5e8445e5bc01e54d
BLAKE2b-256 5e7014cb8748b17e7a7d09cbfaac1616426102e88227bb1d64d08d9aa82ef36d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page