sHedC / python-masterthermconnect

MasterTherm HeatPump API
MIT License
3 stars 2 forks source link

MasterTherm (v2) mappings and findings #8

Closed SeBsZ closed 1 year ago

SeBsZ commented 1 year ago

Note that the mappings I found may apply only to V2, but I think they may be universal. In Device_data_map I've added some new booleans and values. The main one is the ones for sanitary hot water (SHW). Please take a look. I also found actual_temp and requested_temp were not correct, these have been fixed. I renamed 'pads'->'heating_circuits', I'll explain why below.

DEVICE_DATA_MAP = {
    "on": ["bool", "D_3"],
    "hp_function": ["int", "I_51"],  # 0: heating, #1: cooling, #3: auto
    "cooling_mode": ["bool", "D_4"],
    "shw_function": ["bool", "D_66"], #sanitary hot water function available on device
    "shw_enabled": ["bool", "D_275"], #sanitary hot water heating currently active
    "shw_temp": ["float", "A_126"],
    "shw_requested_temp": ["float", "A_129"],
    "compressor_running": ["bool", "D_5"],
    "compressor2_running": ["bool", "D_32"],
    "circulation_pump_running": ["bool", "D_10"],
    "fan_running": ["bool", "D_8"],
    "defrost_mode": ["bool", "D_11"],
    "aux_heater_1": ["bool", "D_6"],
    "aux_heater_2": ["bool", "D_7"],
    "outside_temp": ["float", "A_3"],
    "requested_temp": ["float", "A_5"],
    "actual_temp": ["float", "A_1"],
    "compressor_run_time": ["int", "I_11"],
    "compressor_start_counter": ["int", "I_12"],
    "pump_runtime": ["int", "I_13"],
    "heating_circuits": DEVICE_DATA_PADMAP,
}

These are referred to as hc0-hc6 by MasterTherm. It could mean HeatingCooling or Heating Circuit. I'm calling them circuits for now. It seems there are 6 heating circuits (which can also cool) and two extra circuits called pool and solar. Each heating circuit except pool and solar can also have a pad attached to it (a controller, like a thermostat). I'm still decoding those registers. HC0 is a special case, because it doesn't have a name (seems to be hardcoded 'Home') and is always enabled except when hc1-hc6 are enabled. My house has only 1 heating circuit so only HC0 is used and sanitary hot water which is the same heating circuit as far as I can see. We may need to move 'actual_temp' and 'requested_temp' from device_data_map to hc0 since all the other heating circuits have 'water_temp' and 'water_requested'.

DEVICE_DATA_PADMAP = {
    "hc0": {
        "enabled": ["fixed", False],
        "name": ["string", ["I_211"]],  # hc0 does not have a name
        "on": ["bool", ""],
        "ambient_temp": ["float", "A_211"],
        "ambient_requested": ["float", "A_210"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_35"],
            "setpoint_a_requested": ["float", "A_37"],
            "setpoint_b_outside": ["float", "A_36"],
            "setpoint_b_requested": ["float", "A_38"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_47"],
            "setpoint_a_requested": ["float", "A_49"],
            "setpoint_b_outside": ["float", "A_48"],
            "setpoint_b_requested": ["float", "A_50"],
        }
    },
    "hc1": {
        "enabled": ["fixed", False],
        "name": ["string", ["I_211", "I_212", "I_213", "I_214", "I_215", "I_216"]],
        "on": ["bool", "D_212"],
        "cooling": ["bool", "D_213"],
        "water_temp": ["float", "A_90"],
        "water_requested": ["float", "A_96"],
        "ambient_temp": ["float", "A_216"],
        "ambient_requested": ["float", "A_215"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_101"],
            "setpoint_a_requested": ["float", "A_106"],
            "setpoint_b_outside": ["float", "A_102"],
            "setpoint_b_requested": ["float", "A_107"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_314"],
            "setpoint_a_requested": ["float", "A_315"],
            "setpoint_b_outside": ["float", "A_316"],
            "setpoint_b_requested": ["float", "A_317"],
        },
    },
    "hc2": {
        "enabled": ["fixed", False],
        "name": ["string", ["I_221", "I_222", "I_223", "I_224", "I_225", "I_226"]],
        "on": ["bool", "D_216"],
        "cooling": ["bool", "D_217"],
        "water_temp": ["float", "A_91"],
        "water_requested": ["float", "A_97"],
        "ambient_temp": ["float", "A_222"],
        "ambient_requested": ["float", "A_221"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_108"],
            "setpoint_a_requested": ["float", "A_84"],
            "setpoint_b_outside": ["float", "A_109"],
            "setpoint_b_requested": ["float", "A_85"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_330"],
            "setpoint_a_requested": ["float", "A_331"],
            "setpoint_b_outside": ["float", "A_332"],
            "setpoint_b_requested": ["float", "A_333"],
        },
    },
    "hc3": {
        "enabled": ["fixed", False],
        "name": ["string", ["I_231", "I_232", "I_233", "I_234", "I_235", "I_236"]],
        "on": ["bool", "D_220"],
        "cooling": ["bool", "D_221"],
        "water_temp": ["float", "A_92"],
        "water_requested": ["float", "A_98"],
        "ambient_temp": ["float", "A_228"],
        "ambient_requested": ["float", "A_227"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_108"],
            "setpoint_a_requested": ["float", "A_84"],
            "setpoint_b_outside": ["float", "A_109"],
            "setpoint_b_requested": ["float", "A_85"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_346"],
            "setpoint_a_requested": ["float", "A_347"],
            "setpoint_b_outside": ["float", "A_348"],
            "setpoint_b_requested": ["float", "A_349"],
        },
    },
}
DEVICE_SWITCH_MAP = {
    0: "D_182", #always enabled unless hc1-hc6 are enabled
    1: "D_278",
    2: "D_436",
    3: "D_298",
    4: "D_307",
    5: "D_316",
    6: "D_326",
    7: "D_433",
    8: "D_348"
}

PAD_MAP = {
    0: "hc0", #padz
    1: "hc1", #pada
    2: "hc2", #padb
    3: "hc3", #padc
    4: "hc4", #padd
    5: "hc5", #pade
    6: "hc6", #padf
    7: "pool",
    8: "solar"
}

PAD_MAP may need to be renamed as well. If a house has different controllers/pads, then hc1 is controlled by pada, hc2 by padb, etc. hc0 in my house is controlled by the main padZ.

I'm still working on this, but this is what I have so far. There may be mistakes.

SeBsZ commented 1 year ago

Alright, I found some more. I think we should put this in MasterThermConnect as well and expose it as a variable called Operating Mode. This is what the app/website uses to show the operating mode of the heat pump. Whether it is heating, cooling, heating for domestic hot water (DHW) or pool:

if (t.hp_functionTuv) {
    return "DHW"
} else {
    if (t.pool_v) {
        return "Pool"
    } else {
        if (t.someerror || t.threeerrors_v || !t.hp_Auxheater1OnOff) {
            if (t.hp_CoolingMode) {
                if (t.dewpcontrol_v) {
                    return "Dew point control"
                } else {
                    return "Cooling"
                }
            } else {
                return "Heating"
            }
        } else {
            return "Heating"
        }
    }
}

Let me know if you need the registers for dewpointcontrol and those errors

SeBsZ commented 1 year ago

I figured out a whole list of additional registers. Mostly for errors/alarms/seasons. Not tested yet, waiting for your new code.

DEVICE_DATA_MAP = {
    "hp_power_state": ["bool", "D_3"],
    "hp_function": ["int", "I_51"],  # 0: heating, #1: cooling, #3: auto
    "cooling_mode": ["bool", "D_4"],
    "dhw_function": ["bool", "D_66"],  # domestic hot water heating currently active
    "dhw_enabled": ["bool", "D_275"],  # domestic hot water available on device
    "dhw_temp": ["float", "A_126"],
    "dhw_required_temp": ["float", "A_129"],
    "dhw_min": ["float", "A_296"],
    "dhw_max": ["float", "A_297"],
    "pool_function": ["bool", "D_43"],
    "compressor_running": ["bool", "D_5"],
    "compressor2_running": ["bool", "D_32"],
    "circulation_pump_running": ["bool", "D_10"],
    "fan_running": ["bool", "D_8"],
    "defrost_mode": ["bool", "D_11"],
    "aux_heater_1": ["bool", "D_6"],
    "aux_heater_2": ["bool", "D_7"],
    "outside_temp": ["float", "A_3"],
    "requested_temp": ["float", "A_5"],
    "actual_temp": ["float", "A_1"],
    "compressor_run_time": ["int", "I_11"],
    "compressor_start_counter": ["int", "I_12"],
    "pump_runtime": ["int", "I_13"],
    "aux1_runtime": ["int", "I_100"],
    "aux2_runtime": ["int", "I_101"],
    "dewp_control": ["bool", "D_196"],
    "some_error": ["bool", "D_20"],
    "three_errors": ["bool", "D_21"],
    "reset_3e": ["bool", "D_19"],
    "safety_tstat": ["bool", "D_77"],
    "hdo_on": ["bool", "D_15"],
    "hp_season": ["bool", "D_24"],
    "hp_seasonset": ["int", "I_50"],
    "hp_season_winter": ["float", "A_82"],
    "hp_season_summer": ["float", "A_83"],
    "alarm_a": ["int", "I_20"],
    "alarm_b": ["int", "I_21"],
    "alarm_c": ["int", "I_22"],
    "alarm_d": ["int", "I_23"],
    "alarm_e": ["int", "I_24"],
    "alarm_f": ["int", "I_25"],
    "alarm_g": ["int", "I_26"],
    "alarm_h": ["int", "I_27"],
    "alarm_i": ["int", "I_28"],
    "alarm_j": ["int", "I_39"],
    "alarm_k": ["int", "I_40"],
    "alarm_l": ["int", "I_41"],
    "alarm_m": ["int", "I_42"],
    "heating_circuits": DEVICE_DATA_HCMAP
}

and also did most of the hc4-hc6 registers, heating/cooling curves. Just have pool/solar left, though there is a boolean above that indicates whether pool heating is currently active called pool_function.

DEVICE_DATA_HCMAP = {
    "hc0": {
        "enabled": ["calc"],
        "name": ["string", []],  # hc0 does not have a name
        "on": ["bool", ""],
        "ambient_temp": ["float", "A_211"],
        "ambient_requested": ["float", "A_210"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_35"],
            "setpoint_a_requested": ["float", "A_37"],
            "setpoint_b_outside": ["float", "A_36"],
            "setpoint_b_requested": ["float", "A_38"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_47"],
            "setpoint_a_requested": ["float", "A_49"],
            "setpoint_b_outside": ["float", "A_48"],
            "setpoint_b_requested": ["float", "A_50"],
        }
    },
    "hc1": {
        "enabled": ["calc"],
        "name": [
            "string",
            ["I_211", "I_212", "I_213", "I_214", "I_215", "I_216"],
        ],
        "on": ["bool", "D_212"],
        "cooling": ["bool", "D_213"],
        "water_temp": ["float", "A_90"],
        "water_requested": ["float", "A_96"],
        "ambient_temp": ["float", "A_216"],
        "ambient_requested": ["float", "A_215"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_101"],
            "setpoint_a_requested": ["float", "A_106"],
            "setpoint_b_outside": ["float", "A_102"],
            "setpoint_b_requested": ["float", "A_107"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_314"],
            "setpoint_a_requested": ["float", "A_315"],
            "setpoint_b_outside": ["float", "A_316"],
            "setpoint_b_requested": ["float", "A_317"],
        }
    },
    "hc2": {
        "enabled": ["calc"],
        "name": [
            "string",
            ["I_221", "I_222", "I_223", "I_224", "I_225", "I_226"],
        ],
        "on": ["bool", "D_216"],
        "cooling": ["bool", "D_217"],
        "water_temp": ["float", "A_91"],
        "water_requested": ["float", "A_97"],
        "ambient_temp": ["float", "A_222"],
        "ambient_requested": ["float", "A_221"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_108"],
            "setpoint_a_requested": ["float", "A_84"],
            "setpoint_b_outside": ["float", "A_109"],
            "setpoint_b_requested": ["float", "A_85"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_330"],
            "setpoint_a_requested": ["float", "A_331"],
            "setpoint_b_outside": ["float", "A_332"],
            "setpoint_b_requested": ["float", "A_333"],
        }
    },
    "hc3": {
        "enabled": ["calc"],
        "name": [
            "string",
            ["I_231", "I_232", "I_233", "I_234", "I_235", "I_236"],
        ],
        "on": ["bool", "D_220"],
        "cooling": ["bool", "D_221"],
        "water_temp": ["float", "A_92"],
        "water_requested": ["float", "A_98"],
        "ambient_temp": ["float", "A_228"],
        "ambient_requested": ["float", "A_227"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_108"],
            "setpoint_a_requested": ["float", "A_84"],
            "setpoint_b_outside": ["float", "A_109"],
            "setpoint_b_requested": ["float", "A_85"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_346"],
            "setpoint_a_requested": ["float", "A_347"],
            "setpoint_b_outside": ["float", "A_348"],
            "setpoint_b_requested": ["float", "A_349"],
        }
    },
    "hc4": {
        "enabled": ["calc"],
        "name": [
            "string",
            ["I_241", "I_242", "I_243", "I_244", "I_245", "I_246"],
        ],
        "on": ["bool", "D_50"],
        "cooling": ["bool", "D_224"],
        "water_temp": ["float", "A_93"],
        "water_requested": ["float", "A_99"],
        "ambient_temp": ["float", "A_234"],
        "ambient_requested": ["float", "A_233"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_122"],
            "setpoint_a_requested": ["float", "A_120"],
            "setpoint_b_outside": ["float", "A_88"],
            "setpoint_b_requested": ["float", "A_121"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_362"],
            "setpoint_a_requested": ["float", "A_363"],
            "setpoint_b_outside": ["float", "A_364"],
            "setpoint_b_requested": ["float", "A_365"],
        }
    },
    "hc5": {
        "enabled": ["calc"],
        "name": [
            "string",
            ["I_251", "I_252", "I_253", "I_254", "I_255", "I_256"],
        ],
        "on": ["bool", "D_51"],
        "cooling": ["bool", "D_227"],
        "water_temp": ["float", "A_243"],
        "water_requested": ["float", "A_242"],
        "ambient_temp": ["float", "A_241"],
        "ambient_requested": ["float", "A_240"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_387"],
            "setpoint_a_requested": ["float", "A_388"],
            "setpoint_b_outside": ["float", "A_389"],
            "setpoint_b_requested": ["float", "A_390"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_379"],
            "setpoint_a_requested": ["float", "A_380"],
            "setpoint_b_outside": ["float", "A_381"],
            "setpoint_b_requested": ["float", "A_382"],
        }
    },
    "hc6": {
        "enabled": ["calc"],
        "name": [
            "string",
            ["I_261", "I_262", "I_263", "I_264", "I_265", "I_266"],
        ],
        "on": ["bool", "D_52"],
        "cooling": ["bool", "D_231"],
        "water_temp": ["float", "A_252"],
        "water_requested": ["float", "A_251"],
        "ambient_temp": ["float", "A_250"],
        "ambient_requested": ["float", "A_249"],
        "control_curve_heating": {
            "setpoint_a_outside": ["float", "A_401"],
            "setpoint_a_requested": ["float", "A_402"],
            "setpoint_b_outside": ["float", "A_403"],
            "setpoint_b_requested": ["float", "A_404"],
        },
        "control_curve_cooling": {
            "setpoint_a_outside": ["float", "A_405"],
            "setpoint_a_requested": ["float", "A_406"],
            "setpoint_b_outside": ["float", "A_407"],
            "setpoint_b_requested": ["float", "A_408"],
        }
    }
}
SeBsZ commented 1 year ago

Here's the logic for determining the season settings:

if (hp_seasonset) {
    if (hp_season) {
        "Season: Winter"
    } else {
        "Season: Summer"
    }
} else {
    if (hp_season) {
        "Season: Winter (Auto)"
    } else {
        "Season: Summer (Auto)"
    }
}
sHedC commented 1 year ago

Alright, I found some more. I think we should put this in MasterThermConnect as well and expose it as a variable called Operating Mode. This is what the app/website uses to show the operating mode of the heat pump. Whether it is heating, cooling, heating for domestic hot water (DHW) or pool:

if (t.hp_functionTuv) {
    return "DHW"
} else {
    if (t.pool_v) {
        return "Pool"
    } else {
        if (t.someerror || t.threeerrors_v || !t.hp_Auxheater1OnOff) {
            if (t.hp_CoolingMode) {
                if (t.dewpcontrol_v) {
                    return "Dew point control"
                } else {
                    return "Cooling"
                }
            } else {
                return "Heating"
            }
        } else {
            return "Heating"
        }
    }
}

Let me know if you need the registers for dewpointcontrol and those errors

Moved to separate enhancement #9

sHedC commented 1 year ago

All mappings added and the two other items moved to new issues.

sHedC commented 1 year ago

Released in 1.1.0rc1