前回の記事
「イーサネットとディスプレイデバイスとしてのタブレットを備えた気象ステーション」で、自宅やその他の場所で気象データの収集、保存、処理、および出力をどのように編成したかについて話しました。 また、システムの基礎となる原則により、単に気象データを収集するよりも幅広いものを構築できるようになることも言及され、サーモスタットに関する記事が発表されました。 約束を守り、この非常に熱くなることについて話しましょう。
はじめに
自律暖房を備えた近代的なカントリーハウスには、通常、ガスボイラーが含まれます。 最も原始的なバージョンでは、加熱は2つの方法で制御されます。
- いわば、家の中の一般的なサーモフォンを設定するために、電力が設定され、ボイラーはそれをバッテリーに「ポンプ」します。 通常、電力調整は、加熱回路後の水の温度に関して実行されます。
- 家の中の部屋は異なっているので(異なる窓、壁、主要なポイントなど)、それらも異なる方法で加熱する必要があります。 家全体の暖房回路が1つの場合、この目標はバッテリー自体への水の供給を調整することで達成されます。
同時に、現代のボイラーは原則として外部制御をサポートしています。 この機能の主な目的は、さまざまな種類の温度コントローラーを接続して、バッテリー内の抽象的な水温ではなくボイラー電力を設定できるようにすることです(同じ水温の数値は、外部条件によって完全に異なる結果につながる可能性があります)レギュレーターが設置されている場所の温度。 「帯域外管理」とは何でもかまいませんが、通常は特定の機器メーカーの独自のプロトコル(たとえば、Boschのように)、またはOpenThermプロトコルの実装のいずれかです。
私にとって言及した温度調節器の主な問題は価格です。 約25,000ルーブルのボイラーコストで、9,000ルーブルのレギュレーターの価格はやや高すぎるようです。
ヒキガエルとの二国間協議の結果、推定値が合意されました。これは、典型的な商業規制当局のコストよりも1.5桁低いものでした。その後、国産規制当局の実施オプションの開発が始まりました。
規制当局は次の目標を設定しました。
- 温度センサーがコントロールとして選択されている場所の目標温度を、+ -0.5度の精度で維持する必要があります
- 目標温度を設定できるはずです。
- レギュレータとボイラーの基本的な側面を監視できるようにする必要があります
オープンヘルム
建設の可能性の研究は、外部制御のためのボイラーの能力の研究から始まりました。 ケーシングを取り外した後、ジャンパーが掛かっているコネクタが見つかりました。 ボイラーのドキュメントを調べることで、外部制御用の同じコネクタであることが期待されました。 ここで、私のイタリアのボイラーFerroliのためにロシア語のドキュメントが準備された特別な熱意に言及する必要があります。 ドキュメントには、コネクタの説明があります。 それどころか、私は神聖な碑文「環境の単位」に興味がありました。 直観は、これが主題分野に精通していない翻訳者の仕事であることをしつこくほのめかしました。英語のドキュメントを探す必要があります(より文字通り英語に翻訳されるべきだったため)。 インターネットPDFからボイラーのマニュアルの英語版を掘り下げた後、すべてが明確になり、反対側の同じコネクタが「Room unit」というテキストを誇示しました。 小さなアイコンがあり、ある程度の想像力があれば、OpenThermのロゴと間違える可能性がありました。 「これがあなたの必要なものです」と私は考え、ボイラーで残忍な実験を計画し始めました(窓の外は-25だったので、ヒーターの電子機器を燃やす時が来ました)。
ここで、OpenThermに必要なエクスカーションを行う必要があります。 プロトコルは閉じられておらず、開かれていません。 あなたが仕様を持っているなら、誰もあなたを追いかけないので、閉じていません。 誰もあなたにプロトコル仕様を与えるだけではないので、開いていません。 $$$$$$$のOpenTherm Allianceに参加して、プロトコルの本体にアクセスしてください。 インターネットの奥深くでうろついて、OT2.2仕様を見つけました。
物理レベルでは、OpenThermは約42Vのオープン電圧を持つ2つの低電流ラインです。 制御デバイスは、それらに接続されると、スレーブに同時に電力を供給して制御できます。
仕様では、OT / +およびOT / Liteの2つのプロトコルレベルを定義しています。
1つ目は、IT部門の大多数の人がこの言葉を理解しているという意味でのプロトコルです。 つまり これは、制御デバイス(マスターユニット、ルームユニット、この場合はレギュレーター)とスレーブ(スレーブユニット、これはボイラー)の間で行われる特定のリクエストと回答です。 プロトコルは必須の部分に分かれており、「バーナーのオン/オフ」、「状態の報告」、「加熱回路の後に非常に水温を設定する」パラメーターが含まれます(パラメーターはセットポイントと呼ばれます)。 オプション-炎の変調の制御から、回路内のガスの流れ、圧力、水速度の除去まで、その他の束。 この場合、制御デバイスがこれらのラインの電圧の変化を制御し、スレーブが電流の変化で応答します。
OT / Liteはよりシンプルなものです。 OT / +を実装するほど頭が良くない場合は、ボイラーがセットポイントの設置を制御するデューティサイクルに従って、PWM信号を簡単に生成できます。
さらに、仕様では、ラインを短絡するテストモードも定義しています。 このモードでは、ボイラーは退屈するまで加熱されます(ボイラー自体に取り付けられた水温の上部バーに到達するまで読み取ります)。 したがって、ボイラーは外部レギュレーターなしで動作します(したがって、開口部にジャンパーがかかっています)。
OpenThermが完全ではない
すぐに陰謀を払拭し、OpenThermでボイラーを操縦することは機能しなかったと言います。 インターフェイス回路が組み立てられ、OpenThermのかなり重要な部分を実装するライブラリでさえ書かれましたが、ボイラーは頑固にOpenTherm制御モードへの切り替えを拒否し、応答しませんでした。 より正確には、マイクロコントローラーは答えとして何も登録しませんでした。 ボイラーが答えたかどうか、オシロスコープなしで言うことは不可能です。 この事実を理解するとすぐに、USBオシロスコープ(別名8チャンネルロジックアナライザー、別名USBブラスター)が40個の常緑樹に注文されました(これはただの巨大なものです!)。 予想どおり、オシロスコープは不確実な時期に中国から出発し、熱制御の関連性が冬よりもやや低い春のどこかに来るはずでした。 そのため、少なくとも大まかに結果を確認するために、まったく同じOpenThermテスト機能を使用してボイラーを制御することが決定されました。
ボイラーの操縦方法
長い冬の夜にボイラーを熟考すると、その操作のロジックは非常に単純であるという理解につながりました。 あなたは、水温(設定値)、55℃などを設定します。 温度が60°Cに達するまでウォームアップを開始します。 その後、水温が50°Cに達するとオフになり、再びオンになります。 設定値を中心としたヒステリシスを伴う一種のスイング。 「テスト機能」を使用すると、外部デバイスを使用してボイラーを制御するのが非常に簡単になるため、ボイラーを使用しない場合とまったく同じように動作します。
ボイラーの熟考の別の結果は、家の中でプラスまたはマイナスのバストシューズが快適になるように、通りの温度に応じて、ボイラーに設定する必要がある水温を理解することです。
したがって、ボイラー制御は2つのアルゴリズムで構成されます。
- 希望の設定値と現在の水温に応じたバーナーオン/オフアルゴリズム
- 利用可能な温度データに基づく設定点計算アルゴリズム
ここでは、市場で入手可能なサーモスタットの動作原理に必要な余談をする必要があります。 次の2種類があります。
- クラシック。 動作の原則-本来の温度よりも低温-温めなければなりません、より暖かく-温める必要はありません。 2番目の原則-寒い場合は、非常に暖める必要があります
- OTC(屋外温度補償)を備えたいわゆるレギュレーター、つまり 温度補償レギュレーター。 これらはややこしい。 これらにより、設定値の屋外温度への依存を設定できます。 理論的には、家の温度をより正確に制御する必要があります
部屋と路上の両方に温度データがあるので、原則としてOTCでデバイスを実装できました。 実際、両方のスキームをテストし、実験で確認したところ、2番目の方が収益性が高くなっています。
気象ステーションの実装の結果として、気象データが私の家の周りの空気に現れたことを思い出したいと思います。 サーモスタットのアルゴリズムは次のようになります。
- 空から気象データをキャッチ
- 加熱回路内の水の温度を測定する
- 利用可能なデータに基づいて、回路内の目標水温を計算します
- 回路内の目標水温を維持するためにバーナーを制御します
ハードウェア
ハードウェアは次のものに必要です。
- 空から受信したデータ
- 家の目標温度を設定することができます
- 表示される基本的なインジケータ
- 彼女はボイラー制御の「ラインを短くする」方法を知っていました
- 彼らの仕事とボイラーの動作に関するデータを空中に送り返して、彼らが中央ユニットに捕らえられ、視覚化されるようにする
これらの要件はスキームによって決定されます。

最も単純な部分、つまりボイラー制御部分から始める価値があります。 JP1-2つのボイラー制御ラインが接続されるコネクター。 S1-ボイラー制御ラインを短絡し、したがってオフラインにするトグルスイッチ(コントローラーがどうなるかはわかりません)。 ブリッジD1〜D4は、ボイラーへの接続の極性トレランスを確保するために必要です。 フォトカプラーU1はリレーとして機能し、ボイラーの高電圧制御ライン(開いている場合、これは最大42Vであることを思い出してください)と回路のTTL部分との間にガルバニック絶縁を提供します。 R2は、マイクロコントローラーの(制御が実行される)D5端子を流れる電流が大きすぎないように必要な制限抵抗です。 原則として、この部分は低電流リレーで置き換えることができますが、...私の魂の奥深くでは、ボイラーがOT / +をサポートし、文明的な方法でそれを管理できるという希望があります。 ボイラーとペアリングする実際のスキームは、やや複雑です。 ここでは、ボイラーを閉/開モードで制御するために必要な範囲でのみ説明します。
DS18B20温度センサーは、マイクロコントローラーのピン12に接続されています。 抵抗R4は、仕様に従ってDS18B20のデータピンと電源バスの間に接続されています。
HD44780コントローラーに基づくLCD画面-8文字の2行。 スイッチング回路は古典的です。Vcc-電源バス、Vss-グランド、V0に基準電圧を印加してコントラストを調整します。これは、建物の抵抗R3の正面にあるディバイダーによって形成されます。 R3は一度味わって忘れるためにねじることができます。 R / Wピンはグランドに設定されています。 残りのピンは、コントローラーのRS->ピン11、有効化-> 10、DB4-> 4、DB5-> 7、DB6-> 8、DB7-> 9.のように接続されます。
受信機は端末2に、送信機は端末3に接続されています。
A0は、分圧器を形成する可変抵抗器に接続されます。 端子A0の電圧に基づいて、コントローラーのファームウェアは家の目標温度について結論を出します。
ソフトウェア部
作業のアルゴリズムは次のようになります。

ほとんどの場合、MKは放送中のメッセージを待つ時間を費やします。 設定した時間内にメッセージが届かない場合、アルゴリズムは引き続き本体を実行します(結局、この間に回路内の水の温度が変化する可能性があり、バーナーをオンまたはオフにする時間になる可能性があります)。
これと並行して、A0の電圧測定が行われ、それに応じて住宅内の目標温度が設定されます。 電圧0は18°Cの温度に対応し、電圧Vccは26°Cの温度に対応します。 温度が変化した場合、つまり ユーザーが現在ノブを回すと、画面が更新され、常に3つのパラメーターが表示されます。部屋の目標温度、サーキットの水の温度、現在のサーキットの水の目標温度です。
回路内の目標水温は、次の式を使用して計算されます。
Trrw = 20 +(Trr-To)+(Tr-Trr)* 30、ここで
Trrw-サーキット内の目標水温
Trr-家の目標温度
へ-屋外温度
Tr-家の中の温度
ご覧のとおり、特定のシフト20(ヒューリスティックに選択)という用語があり、OTC(Trr-To)という用語は大きく、部屋の目標温度と外気温の差が大きく、部屋の目標温度に到達しない場合のペナルティ(Tr-Trr)* 30。
アルゴリズムの実装は非常に簡単です。ファームウェアのスケッチを見ると理解できます。
スケッチ#include <TimerTwo.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <VirtualWire.h>
#include <EEPROM.h>
#include <WirelessSensorPipe.h>
#include <LiquidCrystal.h>
#define DEBUG
#define INVALID_TEMPERATURE(1000)
/ *ハードウェア構成* /
#define DSPIN 12
#define TRANSMITPIN 3
#define RECEIVEPIN 2
#define HEATERCONTROLPIN 5
#define TARGETTEMPCONTROLPIN A0
// LCDピンマッピング
#define LCDRS 11
#define LCDENABLE 10
#define LCDD4 4
#define LCDD5 7
#define LCDD6 8
#define LCDD7 9
#define RECEIVETIMEOUT 30 //ワイヤレス受信タイムアウト
bool Heater_enabled = false;
void enable_heater()
{
digitalWrite(HEATERCONTROLPIN、HIGH);
Heater_enabled = true;
}
void disable_heater()
{
digitalWrite(HEATERCONTROLPIN、LOW);
Heater_enabled = false;
}
float target_room_temperature、previous_target_room_temperature;
/ *ポテンショメータから目標室温を読み取り、値が変更された場合にtrueを返します* /
bool updateTargetRoomTemp()
{
uint16_tpotentiometer_value = analogRead(TARGETTEMPCONTROLPIN);
target_room_temperature = 22 + 4 / 1024.0 *ポテンショメーター値;
if(fabs(target_room_temperature-previous_target_room_temperature)<0.1)
{
falseを返します。
}
previous_target_room_temperature = target_room_temperature;
trueを返します。
}
uint16_t cycle_counter = 0;
void targetTempChangeChecker()
{
if(cycle_counter ++%16 == 0)// timer2の最大期間は16ミリ秒なので、16の15サイクルをスロットルアウトして、1秒あたり約4回ターゲット温度値を更新します
{
if(updateTargetRoomTemp())
updateOnScreenInfo();
}
}
#define OUTSIDE_SENSOR_ID 27327
#define ROOM_SENSOR_ID 13467
#define TEMPERATURE_HYSTERESIS 5
#define HEATER_MAX_TEMP 80
#define HEATER_MIN_TEMP 30
float room_temperature = INVALID_TEMPERATURE;
float outside_temperature = INVALID_TEMPERATURE;
float RW_temperature;
float target_RW_temperature = 30;
OneWire one_wire(DSPIN);
ダラス温度センサー(&one_wire);
void updateTargetRWTemperature()
{
sensor.requestTemperatures();
RW_temperature = sensor.getTempCByIndex(0);
target_RW_temperature = 20 +(target_room_temperature-outside_temperature)+(target_room_temperature-room_temperature)* 30;
target_RW_temperature = min(target_RW_temperature、HEATER_MAX_TEMP);
target_RW_temperature = max(target_RW_temperature、HEATER_MIN_TEMP);
}
LiquidCrystal lcd(LCDRS、LCDENABLE、LCDD4、LCDD5、LCDD6、LCDD7);
void updateOnScreenInfo()
{
char floatBuffer [7];
lcd.setCursor(0,0);
lcd.print(F( "部屋"));
lcd.print(dtostrf(target_room_temperature、2、1、floatBuffer));
lcd.setCursor(0,1);
lcd.print(F( "W"));
lcd.print((int)RW_temperature);
lcd.print(F( "TW"));
lcd.print((int)target_RW_temperature);
}
WirelessSensorPipeパイプ。
void setup()
{
#ifdef DEBUG
Serial.begin(9600);
Serial.println(F( "Entered setup"));
#endif
pinMode(HEATERCONTROLPIN、OUTPUT);
sensor.begin();
pipe.begin(TRANSMITPIN、RECEIVEPIN、13);
#ifdef DEBUG
Serial.print(F( "センサーID:"));
Serial.println(pipe.id());
#endif
updateTargetRoomTemp();
updateTargetRWTemperature();
TimerTwo :: init(16384、targetTempChangeChecker);
TimerTwo :: start();
lcd.begin(8、2);
}
int current_transmission_phase = 0;
ボイドループ()
{
#ifdef DEBUG
Serial.print(F( "タイムスタンプ:"));
Serial.println(millis()/ 1000);
Serial.print(F(“ RW温度:„));
Serial.println(RW_temperature);
Serial.print(F(“ target_RW温度:„));
Serial.println(target_RW_temperature);
Serial.print(F(「外気温度:„));
Serial.println(outside_temperature);
Serial.print(F(“室温:„));
Serial.println(room_temperature);
Serial.print(F(「目標室温:„」);
Serial.println(target_room_temperature);
// LEDを点滅させて、読み取りが完了したことを示します
// digitalWrite(13、HIGH);
//遅延(100);
// digitalWrite(13、LOW);
#endif
updateTargetRoomTemp();
lcd.begin(8.2); //何らかの理由でLCDが定期的に狂ってしまうので、これはこの状態から抜け出すための一時的なハックです。 そのような行動の理由が明らかになったときに削除されます。
lcd.clear();
updateOnScreenInfo();
WirelessSensorPipe ::パケットパケット。
if(pipe.receive(パケット、RECEIVETIMEOUT * 1000))
{
if(packet.type == WirelessSensorPipe :: TEMPERATURE)
{
スイッチ(packet.id)
{
ケースOUTSIDE_SENSOR_ID:
outside_temperature = packet.value;
休憩;
ケースROOM_SENSOR_ID:
room_temperature = packet.value;
休憩;
}
}
帰る //残りのコードをスキップして、データの送信と、データを連続して送信する他のデバイスとの競合を回避します。 つまり、誰かが送信するまで待機し、誰も送信しない場合は残りの作業を実行します
}
updateTargetRWTemperature();
if(RW_temperature> = target_RW_temperature + TEMPERATURE_HYSTERESIS && target_RW_temperature <HEATER_MAX_TEMP)
{
disable_heater();
}
if(RW_temperature <= target_RW_temperature-TEMPERATURE_HYSTERESIS && target_RW_temperature> HEATER_MIN_TEMP)
{
enable_heater();
}
スイッチ(current_transmission_phase ++)
{
ケース0:
pipe.send(WirelessSensorPipe :: TEMPERATURE、room_temperature);
休憩;
ケース1:
pipe.send(WirelessSensorPipe :: HEATERSETPOINT、target_RW_temperature);
休憩;
ケース2:
pipe.send(WirelessSensorPipe :: HEATERRWTEMPERATURE、RW_temperature);
休憩;
ケース3:
pipe.send(WirelessSensorPipe :: HEATERTARGETROOMTEMPERATURE、target_room_temperature);
休憩;
ケース4:
pipe.send(WirelessSensorPipe :: HEATERFLAMEENABLED、heater_enabled);
current_transmission_phase = 0;
休憩;
}
}
画面を操作すると、ほとんどの問題が発生することに注意してください。 不適切な接続や初期化など、子供のただれについては説明しませんが、タイマーの不正確な使用に関連する問題については言及できます。 実際には、最初のタイマー実装はA0を読み取り、温度を計算し、画面を確実に更新しました。 リフレッシュレートは2 Hzと非常に高く、画面の更新手順は非常に時間がかかりました。 これは、アルゴリズムのメインループ(ほとんどの時間を空中から受信しようとすることに費やされる)が、タイマーハンドラーによって長い間中断されるという事実につながりました。 これにより、受信機のソフトウェア部分は、タイマーハンドラーの注意散漫中に多くのことを逃したため、空中から何も受信できませんでした。 さらに、画面がときどき狂ってしまい、元に戻すには再初期化する必要があります。 この動作の理由は何ですか、わかりません。
私が遭遇した2番目の問題-コントローラーが最初に設置された場所は、残忍な無線の影の場所であることが判明しました。
これらの2つの問題により、コントローラーが何も受け入れない理由を解明しようとしてかなりの夜を奪われました。 最も正反対は、それらのいずれかを削除しても状況が改善されなかったため、両方を同時に解決する必要があったため、かなり長い間、「無線の影はそれとは関係ありません」および「すべてが受信側と正常になっている」などのエラーが発生しました。
もう1つの非常に悪いアイデアは、アルゴリズムの各反復で、すべての制御されたパラメーターを一括して無線に転送することでした。 送信されるパラメーターには、部屋の温度、通りの温度(制御目的での繰り返し)、家の設定目標温度、水温の計算された目標値、水温の現在値、ボイラー制御回路が閉じているかどうかが含まれます。 アルゴリズムの1回の反復の実行には約30秒かかるため、パケットの束が1分間に2回空中に落ち、衝突の確率が増加しました。 したがって、1回の反復で1つのパラメーターのみを空中に送信するようにファームウェアを変更する必要がありました。 したがって、各パラメーターは3分ごとに更新され始めました。
パーツリスト
Arduino Pro Mini -100ルーブルずつ
DS18B20-34個ずつこする
トランスミッター+レシーバー433MHz -40ルーブル
LCD WH0802A-NGG-CT -125ルーブルずつ
4N35-9ルーブルずつ
ダイオードブリッジDB107-5.5ルーブルずつ
抵抗器-わずか5ルーブル
トグルスイッチ(オフラインで購入)-20ルーブル
ケースKR-606-PS -40ルーブル
結果-はんだ、ブレッドボード、ワイヤ、はんだごての減価償却費を考慮して-約450ルーブル。 EbayでLCDを注文した場合、さらに80ルーブル安くなります。
テスト、結論、計画
コントローラー自体とスポイラーの下のボイラーの写真。 LCDの下の不均等にカットされたウィンドウをおIびします。
しかし、DS18B20はボイラー出口にねじ止めされています
「コントロールパネル」が同じStrikeでどのように見えるかの写真。
私が言ったように、2つの制御スキームが実装されました-古典的な、すなわち 「熱くない?」 私たちは揚げます!」、そして街路温度の補正を行います。
原則として、最初のものは最初に提示システムに提示された要件を満たしました。 目標値の半分の範囲内の室温を提供しました。 ただし、デメリットは、この目標値の前後の変動であり、振幅はほぼ0.5度です。 つまり 室内の温度はターゲットの周りで振動しました。この振動は、外部要因が安定しているため、明らかに外部要因によるものではありませんでした。
しかし、OTCの導入は予想外の良い結果をもたらしました。 上記の式に従ってアルゴリズムに従って作業すると、温度がターゲットから-0.2 + 0.1度以内に安定しました。 0.2度の低下は体温調節プロセスの特性とは関係がありませんが、誰かが温水を開くと(たとえば、洗浄に30分かかります)、ボイラーは給湯回路で温水を確実に加熱するために忙しいことに注意してください。 加熱回路は加熱しません。

このモードのコントローラーは半月作動しており、飛行は正常で、故障はありませんでした。 サーモスタットは心理的な快適さをきちんと高めていると言えます。 以前は、少なくとも夜と朝ごとに水温を設定する必要がありましたが、現在の路上温度、予測と自分の直感の証言に応じて努力が必要でしたが、ボイラーがあることを覚えていません-それはそれ自体で動作します。
計画はOT / +を絞ることを意味し、注文したオシロスコープの利点がありましたが、その助けを借りて、間違ったものをボイラーに送ったことも既にわかりました(コードにありがちなタイプミスがあり、確認していませんでした-私の目はぼやけました)私は一般的に黙っています。 原則として、これはサーモスタットの動作を改善しませんが、より多くの診断を撮影することを可能にします。 さらに、これは「誰」というカテゴリーの根本的な問題になりました。