ムニエルブログ

江戸川区在住のアプリケーションエンジニア


エアコン本体とリモコンの温度設定にズレが生じる問題〜プログラムによる再現〜

最近すっかり気温が高くなってきて、夏の訪れを感じています。
僕の部屋は夏になると室温が30度を超えるため、エアコンが欠かせません。

エアコンといえば、子供の頃エアコンの動作について疑問だったことがあります。
それは、エアコン本体とリモコンの温度設定にズレが生じるのではないかということです。

エアコン本体とリモコンの温度設定にズレが生じる問題

たとえば、本体とリモコンの温度設定がともに28度だったとします。
このとき、リモコンの温度下ボタンを押しましたが、向きが悪く信号が本体まで届きませんでした。
当然本体は28度のままですが、リモコンには27度と表示されています。
この時点で、本体とリモコンの温度設定にズレが生じてしまいました。

このズレを解消するため、今度はリモコンを本体に向けて温度上ボタンを押してみます。
双方の温度が上がった結果、本体は29度となり、リモコンには28度と表示されています。
本体に温度表示がない場合、もはやユーザーがこのズレに気づく手段はありません。

これが、幼少期の僕が考えていたエアコン本体とリモコンの温度設定にズレが生じる問題です。

もっとも、実際にはこのような問題は発生しません。
なぜなら、リモコンの温度ボタンを押したときに本体に送られる信号は「温度を1度上げる」のような相対指定ではなく、「温度を28度にする」のような絶対指定になっているからです。*1
とはいえ、ポンコツメーカーのつくるエアコンにおいてはその限りではありません。

プログラムによる再現

普通のエアコンとポンコツエアコンについて、Javaのプログラムで再現してみます。

ソースコード

HasPowerButton.java

/**
 * 電源ボタン保持インターフェース
 */
public interface HasPowerButton {
    /**
     * 電源ボタンを押します。
     */
    void pushPowerButton();
}

エアコンもリモコンも電源ボタンがあるので、共通のインターフェースとして定義します。

AirConditioner.java

import java.util.function.Consumer;

/**
 * エアコン
 */
public abstract class AirConditioner implements HasPowerButton {
    /** 電源 */
    protected boolean power;
    /** 温度 */
    protected int temperature;

    /**
     * @param power 電源
     * @param temperature 温度
     */
    public AirConditioner(boolean power, int temperature) {
        this.power = power;
        this.temperature = temperature;
    }

    /**
     * 電源を切り替えます。
     */
    public void togglePower(){
        power = !power;
    }

    /**
     * 温度を上げます。
     */
    public void plusTemperature() {
        temperature++;
    }

    /**
     * 温度を下げます。
     */
    public void minusTemperature() {
        temperature--;
    }

    /**
     * 信号を受信して実行します。
     * @param signal 信号:自身 -> {...}
     */
    public void receiveSignal(Consumer<AirConditioner> signal){
        signal.accept(this);
    }

    public boolean getPower() {
        return power;
    }

    public void setPower(boolean power) {
        this.power = power;
    }

    public int getTemperature() {
        return temperature;
    }

    public void setTemperature(int temperature) {
        this.temperature = temperature;
    }
}

エアコンの抽象クラスです。
receiveSignalメソッドで、リモコンからの信号を受信して実行します。
信号は、関数型インターフェースのConsumerで表しています。

NormalAirConditioner.java

/**
 * 普通のエアコン
 */
public class NormalAirConditioner extends AirConditioner {
    public NormalAirConditioner() {
        super(false, 28);
    }

    @Override
    public void pushPowerButton(){
        togglePower();
    }
}

普通のエアコンです。
電源がオフの時に電源ボタンを押すとオンになり、オンのときに押すとオフになります。

JunkAirConditioner.java

/**
 * ポンコツエアコン
 */
public class JunkAirConditioner extends AirConditioner {
    public JunkAirConditioner() {
        super(false, 28);
    }

    @Override
    public void pushPowerButton(){
        togglePower();
    }
}

ポンコツエアコンです。
本体自体は普通のエアコンと変わりません。

RemoteController.java

/**
 * リモコン
 */
public abstract class RemoteController implements HasPowerButton{
    /** エアコン */
    protected final AirConditioner conditioner;
    /** 電源 */
    protected boolean power = false;
    /** 温度 */
    protected int temperature = 28;
    /** リモコンがエアコンに向いているか */
    protected boolean facing = false;

    /**
     * @param conditioner エアコン
     */
    public RemoteController(AirConditioner conditioner) {
        this.conditioner = conditioner;
    }

    /**
     * リモコンをエアコンに向けます。
     */
    public void face() {
        System.out.println("face to air conditioner");
        facing = true;
    }

    /**
     * リモコンをエアコンから背けます。
     */
    public void unface() {
        System.out.println("unface from air conditioner");
        facing = false;
    }

    /**
     * 温度上ボタンを押します。
     */
    public abstract void pushUpButton();

    /**
     * 温度下ボタンを押します。
     */
    public abstract void pushDownButton();

    public boolean getPower() {
        return power;
    }

    public void setPower(boolean power) {
        this.power = power;
    }

    public int getTemperature() {
        return temperature;
    }

    public void setTemperature(int temperature) {
        this.temperature = temperature;
    }

    public boolean getFacing() {
        return facing;
    }

    public void setFacing(boolean faseing) {
        this.facing = faseing;
    }

    public AirConditioner getConditioner() {
        return conditioner;
    }
}

リモコンの抽象クラスです。
「リモコンがエアコンに向いているか」が鍵となります。

NormalRemoteController.java

/**
 * 普通のリモコン
 */
public class NormalRemoteController extends RemoteController {
    /**
     * @param conditioner エアコン
     */
    public NormalRemoteController(NormalAirConditioner conditioner) {
        super(conditioner);
    }

    @Override
    public void pushPowerButton() {
        System.out.println("push power button");
        power = !power;
        if(facing){
            //電源をリモコンと同じ状態にする信号を送信
            conditioner.receiveSignal(c -> c.setPower(power));
        }
    }

    @Override
    public void pushUpButton() {
        System.out.println("push up button");
        temperature++;
        if(facing){
            //温度設定をリモコンと同じ状態にする信号を送信
            conditioner.receiveSignal(c -> c.setTemperature(temperature));
        }
    }

    @Override
    public void pushDownButton() {
        System.out.println("push down button");
        temperature--;
        if(facing){
            //温度設定をリモコンと同じ状態にする信号を送信
            conditioner.receiveSignal(c -> c.setTemperature(temperature));
        }
    }
}

普通のリモコンです。
各種ボタンを押した際、リモコンと同じ状態にする信号を本体に送ります。

JunkRemoteController.java

/**
 * ポンコツリモコン
 */
public class JunkRemoteController extends RemoteController {
    /**
     * @param conditioner エアコン
     */
    public JunkRemoteController(JunkAirConditioner conditioner) {
        super(conditioner);
    }

    @Override
    public void pushPowerButton() {
        System.out.println("push power button");
        power = !power;
        if(facing){
            //電源を切り替える信号を送信
            conditioner.receiveSignal(c -> c.togglePower());
        }
    }

    @Override
    public void pushUpButton() {
        System.out.println("push up button");
        temperature++;
        if(facing){
            //温度を上げる信号を送信
            conditioner.receiveSignal(c -> c.plusTemperature());
        }
    }

    @Override
    public void pushDownButton() {
        System.out.println("push down button");
        temperature--;
        if(facing){
            //温度を下げる信号を送信
            conditioner.receiveSignal(c -> c.minusTemperature());
        }
    }
}

ポンコツリモコンです。
各種ボタンを押した際、リモコンの状態に関係なく相対的に変化するような信号を本体に送ります。

AirConditionerUser.java

/**
 * エアコンユーザー
 */
public class AirConditionerUser {
    public static void main(String[] args) {
        NormalAirConditioner normalConditioner = new NormalAirConditioner();
        NormalRemoteController normalRemote = new NormalRemoteController(normalConditioner);
        System.out.println("use normal air conditioner");
        useAirConditioner(normalConditioner, normalRemote);

        System.out.println();

        JunkAirConditioner junkConditioner = new JunkAirConditioner();
        JunkRemoteController junkRemote = new JunkRemoteController(junkConditioner);
        System.out.println("use junk air conditioner");
        useAirConditioner(junkConditioner, junkRemote);
    }

    /**
     * エアコンを使います。
     * @param conditioner エアコン
     * @param remote リモコン
     */
    private static void useAirConditioner(AirConditioner conditioner, RemoteController remote){
        //エアコンの電源を入れる
        conditioner.pushPowerButton();

        //リモコンの電源を入れる
        remote.pushPowerButton();
        seeTemperature(conditioner, remote);

        //リモコンの温度下ボタンを押す
        remote.pushDownButton();
        seeTemperature(conditioner, remote);

        //本体とリモコンのリモコンの温度設定がずれたので、リモコンをエアコンに向ける
        remote.face();

        //リモコンの温度上ボタンを押す
        remote.pushUpButton();
        seeTemperature(conditioner, remote);
    }

    /**
     * エアコンとリモコンの温度を確認します。
     * @param conditioner エアコン
     * @param remote リモコン
     */
    private static void seeTemperature(AirConditioner conditioner, RemoteController remote){
        System.out.println("c=" + conditioner.getTemperature() + ",r=" + remote.getTemperature());
    }
}

エアコン使用クラスです。
普通のエアコンとポンコツエアコンでまったく同じ動作をしてみて、違いを検証します。

実行結果

use normal air conditioner
push power button
c=28,r=28
push down button
c=28,r=27
face to air conditioner
push up button
c=28,r=28

use junk air conditioner
push power button
c=28,r=28
push down button
c=28,r=27
face to air conditioner
push up button
c=29,r=28

見ての通り、普通のエアコンでは絶対指定の信号を送っているため、温度設定がリモコン側に同期されます。
一方、ポンコツエアコンでは相対指定の信号を送っているため、一度温度設定がずれてしまうと半永久的にずれたままとなります。

あなたの家のエアコンは、大丈夫ですか?


エアコンのいらない家

エアコンのいらない家