# Air conditioner

処理

# 実装ブロック

名前ID説明
Daikin BRP069daikin_brp069
Air conditioner
P
M
TT
FS
SV
SH
CLN
P
M
TT
FS
SV
SH
CLN
RT
F

# 入力

ID略称名前型デフォルト説明
powerPpowerBOOLEANfalse
modeMmodeNUMBER0
target_tempTTtarget_tempNUMBER21.0
fan_speedFSfan_speedNUMBER0
swing_vSVswing_vNUMBER0
swing_hSHswing_hNUMBER0
air_cleanCLNair_cleanBOOLEANfalse

# 出力

ID略称名前型デフォルト説明
powerPpowerBOOLEANfalse
modeMmodeNUMBER0
target_tempTTtarget_tempNUMBER0.0
fan_speedFSfan_speedNUMBER0
swing_vSVswing_vNUMBER0
swing_hSHswing_hNUMBER0
air_cleanCLNair_cleanBOOLEANfalse
room_tempRTroom_tempNUMBER-1000.0
faultFfaultNUMBER0

# 設定

ID名前型デフォルト単位説明
min_target_tempmin_target_tempNUMBER10.0°C

詳細:

≤ max_target_temp
max_target_tempmax_target_tempNUMBER30.0°C

詳細:

≥ min_target_temp

# 状態

ID名前型デフォルト単位説明
unit_powerunit_powerNUMBER-1
unit_modeunit_modeNUMBER-1
unit_target_tempunit_target_tempNUMBER-1000.0°C
unit_room_tempunit_room_tempNUMBER-1000.0°C
unit_faultunit_faultNUMBER0
invoke_rcinvoke_rcNUMBER0
sentsentBOOLEANfalse
sent_powersent_powerBOOLEANfalse
sent_modesent_modeNUMBER0
sent_target_tempsent_target_tempNUMBER0.0°C
sent_fan_speedsent_fan_speedNUMBER0
sent_swing_vsent_swing_vNUMBER0
sent_swing_hsent_swing_hNUMBER0
sent_air_cleansent_air_cleanBOOLEANfalse

# ソースコード

Volang ソースを表示
// Air conditioner - abstract block.
//
// Turns the input channels into one desired unit state and hands it to the
// attached implementation (driver), the only part that knows how to reach a
// particular unit (IR, LAN, Modbus, ...).
//
// Value encodings, shared by the inputs, the outputs and the driver call:
//   mode       0 auto, 1 heating, 2 cooling, 3 drying, 4 fan only
//   fan_speed  0 auto, 1 quiet, 2 low, 3 medium, 4 high, 5 powerful
//   swing_v    0 auto, 1 swing, 2..6 fixed vane (2 highest .. 6 lowest)
//   swing_h    0 auto, 1 swing, 2..6 fixed vane (2 leftmost .. 6 rightmost)
//   fault      0 none, -1 unit unreachable, > 0 unit specific error code
// A unit that cannot do what was asked for falls back to its closest
// equivalent - that mapping belongs to the driver.
//
// The driver must declare one function:
//
//   ac_apply(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean)
//       Pushes the complete desired state, called whenever a value changes.
//       It only has to accept the work, not finish it: a driver on the network
//       returns as soon as the request is out, and one still busy with an
//       earlier exchange keeps the state and sends it once that is over.
//       Returns 0 when accepted, otherwise an error code that is published on
//       the fault output.
//
// Whether and how often the unit is polled for its status is up to the driver,
// which can be scheduled on its own. Either way it reports back through this
// block's state, then returns non-zero from the run that stored the readings,
// so the runtime calls std::on_driver_update here:
//   unit_power        -1 unknown, 0 off, 1 on
//   unit_mode         -1 unknown, otherwise a mode value
//   unit_target_temp  -1000 unknown, otherwise °C
//   unit_room_temp    -1000 unknown, otherwise °C
//   unit_fault        the fault value to publish
// Whatever is left unknown is published as the value this block commanded.

fn choice(value, hi) {
    v = math::int(math::round(value))
    if (v < 0) {
        return 0
    }
    if (v > hi) {
        return hi
    }
    return v
}

fn clamp(value, lo, hi) {
    if (value < lo) {
        return lo
    }
    if (value > hi) {
        return hi
    }
    return value
}

// Airflow and air cleaning have no counterpart in the readings - no unit
// reports them back - so they are published exactly as commanded.
fn publish(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean) {
    unit_power = state::get("unit_power")
    if (unit_power >= 0) {
        power = unit_power != 0
    }
    unit_mode = state::get("unit_mode")
    if (unit_mode >= 0) {
        mode = unit_mode
    }
    unit_target_temp = state::get("unit_target_temp")
    if (unit_target_temp > -1000) {
        target_temp = unit_target_temp
    }
    fault = state::get("unit_fault")
    if (fault == 0) {
        fault = state::get("invoke_rc")
    }
    output::set("power", power)
    output::set("mode", mode)
    output::set("target_temp", target_temp)
    output::set("fan_speed", fan_speed)
    output::set("swing_v", swing_v)
    output::set("swing_h", swing_h)
    output::set("air_clean", air_clean)
    output::set("room_temp", state::get("unit_room_temp"))
    output::set("fault", fault)
}

fn changed(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean) {
    if (!state::get("sent")) {
        return true
    }
    if (state::get("sent_power") != power) {
        return true
    }
    if (state::get("sent_air_clean") != air_clean) {
        return true
    }
    if (state::get("sent_mode") != mode) {
        return true
    }
    if (state::get("sent_target_temp") != target_temp) {
        return true
    }
    if (state::get("sent_fan_speed") != fan_speed) {
        return true
    }
    if (state::get("sent_swing_v") != swing_v) {
        return true
    }
    if (state::get("sent_swing_h") != swing_h) {
        return true
    }
    return false
}

// The last readings describe the unit before a command, so they must not mask
// what was just asked for; the read that follows fills them in again. The room
// temperature is a measurement, not a setting, and stays.
fn forget_readings() {
    state::set("unit_power", -1)
    state::set("unit_mode", -1)
    state::set("unit_target_temp", -1000.0)
}

fn remember(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean) {
    state::set("sent_power", power)
    state::set("sent_mode", mode)
    state::set("sent_target_temp", target_temp)
    state::set("sent_fan_speed", fan_speed)
    state::set("sent_swing_v", swing_v)
    state::set("sent_swing_h", swing_h)
    state::set("sent_air_clean", air_clean)
    state::set("sent", true)
}

// Called by the runtime after the driver stored fresh readings. The commanded
// values are only a fallback for whatever the unit did not report.
extern fn std::on_driver_update() {
    power = state::get("sent_power")
    mode = state::get("sent_mode")
    target_temp = state::get("sent_target_temp")
    fan_speed = state::get("sent_fan_speed")
    swing_v = state::get("sent_swing_v")
    swing_h = state::get("sent_swing_h")
    air_clean = state::get("sent_air_clean")
    publish(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean)
}

power = input::get("power")
mode = choice(input::get("mode"), 4)
fan_speed = choice(input::get("fan_speed"), 5)
swing_v = choice(input::get("swing_v"), 6)
swing_h = choice(input::get("swing_h"), 6)
air_clean = input::get("air_clean")
min_temp = config::get("min_target_temp")
max_temp = config::get("max_target_temp")
target_temp = clamp(input::get("target_temp"), min_temp, max_temp)

if (changed(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean)) {
    // Report the commanded state right away, so the outputs stay meaningful
    // even when the driver call below fails or no driver is attached at all.
    publish(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean)
    rc = std::invoke("ac_apply", power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean)
    state::set("invoke_rc", rc)
    if (rc == 0) {
        remember(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean)
        forget_readings()
    }
}
publish(power, mode, target_temp, fan_speed, swing_v, swing_h, air_clean)
Voldeno スマートホーム自動化における Air conditioner Logic Block の動作、用途、設定方法を説明します。