
プロジェクトをビルドし、テストを実行してコードの品質を確認するために、( Mail.ru Calendarプロジェクトで)Jenkins CIを使用します。 アセンブリはgitリポジトリに(フックで)プッシュした直後に開始されます。もちろん、失敗したアセンブリに関する情報をタイムリーに受け取りたいと思います。 一方で、電子メール通知で十分であるように思われますが、他方では、もっと目立って楽しいものが欲しいです。
約3、4年前、私が別のプロジェクトに取り組んでいたとき、同じ目的で、220ボルトのネットワークで動作するフラッシャーが購入され、それを制御するために、悪名高いMasterKit社のMP709モジュール(USBリレー)が購入されました。 ソリューションは成功しませんでした:まず、このモジュールのLinuxサポートがありませんでした(データ交換プロトコルを逆にして、Linux用の独自の「ドライバー」を作成する必要がありました)。次に、非常灯の場所がコンピューターとコンセントからの配線によって制限されていました。 いずれにせよ、デザインは遠くの箱に捨てられ、翼で待っていました。
最近、私の手は再びcombき、私は何か面白いことをしたかったが、役に立たなかったので、フラッシャーを思い出しました。 ゴミの山に飛び込んで、そこから釣り上げました:Arduino Nano-2個、リレーモジュール-1個、MX-05Vレシーバー-1個、MX-FS-03Vトランスミッター-1個。 残りのゴミをバルコニーの隅に投げ込み、次の1時間を待って、デバイスの組み立てを始めました。
叙情的なst迷 :昔、私が若くて多くの時間を過ごしていたとき、私はいくつかのAVRマイクロコントローラーを使用し、ボードをエッチングし、デバイスをはんだ付けし、アセンブリ言語でプログラムします...出口で。 プロセスからより多くの喜びがあり、結果は同じです。
ハードウェア
回路は非常にシンプルであることが判明しました。なぜなら、私たちの時代には膨大な数の異なる電子モジュール、設計者、ブロックにより、はんだごてを手に入れたことがなく、回路やプログラミングを勉強していない人のために電子デバイスを組み立てることができたからです。送信機(Arduino Nano + MX-FS-03V)

レシーバー(MX-05V + Arduino Nano +リレーモジュール):

操作の原理はさらにシンプルです。ArduinoはコンピューターのUSBポートに接続し、シリアルインターフェイスを介してコマンドをリッスンします。 コマンドが有効な場合、無線送信機を介して送信されます。 2番目のブロックでは、別のArduinoがレシーバーをリッスンし、コマンドを受信すると、リレーをオンまたはオフにします。 それだけです フィードバック、チェック(チェックサム)、ロジックはありません。
送信機プログラムは次のとおりです。
#include <VirtualWire.h>
int ledPin = 13 ; // LEDをピンで留める
char incoming_byte ; //着信メッセージを保存するバッファ
char input_data [ 12 ] ; //メッセージのサイズ
int input_size = 0 ; //カウンター、カウンターのみ
void setup ( ) {
// LEDピンを設定します
pinMode ( ledPin、OUTPUT ) ;
digitalWrite ( ledPin、LOW ) ;
//シリアルを初期化します(9600 bps)
シリアル 開始 ( 9600 ) ;
シリアル println ( "準備完了" ) ;
// IOとISRを初期化します
vw_set_ptt_inverted ( true ) ; // DR3100に必要
vw_setup ( 1200 ) ; //ビット/秒
}
voidループ( ) {
while ( Serial。available ( ) > 0 ) {
incoming_byte =シリアル。 読む ( ) ; //着信バイトを読み取ります
if ( incoming_byte == 'n' ) {
input_data [ input_size ++ ] = 0 ;
if ( strncmp ( input_data、 "Achtung ON" 、 10 ) == 0 || strncmp ( input_data、 "Achtung ON" 、 11 ) == 0 ) {
digitalWrite ( ledPin、HIGH ) ;
vw_send ( ( uint8_t * ) input_data、input_size ) ;
vw_wait_tx ( ) ; //メッセージ全体がなくなるまで待つ
digitalWrite ( ledPin、LOW ) ;
シリアル println ( "OK" ) ;
} else {
シリアル println ( "FAIL" ) ;
}
while ( input_size- > = 0 ) {
input_data [ input_size ] = 0 ;
}
input_size = 0 ; //カウンタをリセットします
} else {
if ( input_size <= 11 ) {
input_data [ input_size ] = incoming_byte ;
}
input_size ++ ;
}
}
}
受信機プログラム:
#include <VirtualWire.h>
int ledPin = 13 ; // LEDをピンで留める
int relayPin = 3 ; //リレーが付いたピン
バイトinput_data [ VW_MAX_MESSAGE_LEN ] ; //着信メッセージを保存するバッファ
バイトinput_size = VW_MAX_MESSAGE_LEN ; //メッセージのサイズ
void setup ( ) {
// LEDピンを設定します
pinMode ( ledPin、OUTPUT ) ;
digitalWrite ( ledPin、LOW ) ;
//リレーピンを設定します
pinMode ( relayPin、OUTPUT ) ;
digitalWrite ( relayPin、HIGH ) ;
// IOとISRを初期化します
vw_set_ptt_inverted ( true ) ; // DR3100に必要
vw_setup ( 1200 ) ; //ビット/秒
vw_rx_start ( ) ; //レシーバーを起動します
}
voidループ( ) {
//処理するデータがあるかどうかを確認します
if ( vw_get_message ( input_data、 & input_size ) ) {
digitalWrite ( ledPin、HIGH ) ;
if ( strncmp ( ( char * ) input_data、 "Achtung ON" 、 10 ) == 0 ) {
digitalWrite ( relayPin、LOW ) ; // achtung! リレーをオンにする
} else if ( strncmp ( ( char * ) input_data、 "Achtung OFF" 、 11 ) == 0 ) {
digitalWrite ( relayPin、HIGH ) ; //リレーをオフにします
} else {
遅延( 1000 ) ;
}
digitalWrite ( ledPin、LOW ) ;
}
}
ご覧のとおり、すべてが非常に簡単です。 マイクロコントローラーを接続し、Arduinoプログラムに組み込まれたブートローダーを使用して、レシーバーとトランスミッターをそれぞれフラッシュし、トランスミッターに接続された「シリアルモニター」を実行し、リレーのオン/オフコマンドと無効なコマンド(チェック用)を送信します。

リレーがオンとオフになり、すべてが機能し、すべてが正常です。
フラッシャーを分解して、レシーバーとリレーの配置場所を確認します。

内部に多くのスペースがあることがわかります。 デバイスの組み立てを開始しますが、最初に受信機の電力に対処する必要があります。
私はちょうどそれをやりました。ノキアの携帯電話から不要になった古い電源を取り、それを分解して、220ボルトの受信機に電力を供給できる小さなボードを手に入れました。 ケースからボードを取り外すプロセスは非常に困難であることに注意せざるを得ませんでした。 ケースは高品質のプラスチックで作られています。 それにもかかわらず、私は成功しました:

受信機と電源でフラッシャーを組み立てます:

すべてが機能することを確認します。ネットワーク内のデバイスの電源を入れ、「シリアルモニター」経由で「Achtung ON」コマンドをトランスミッターに送信します。 リレーがクリックされ、ライトが点灯し、エンジンが回転し、歓声が上がりました! 「Achtung OFF」コマンドを送信します-すべてが停止しました。 点滅するライトは機能しています。 ネジと中国のホットメルト接着剤でボードを取り付け、構造全体を元の形に組み立てるだけです。
送信機を使用して、私は式典に立たず、すべてを一緒にはんだ付けすることにしました:

将来的には、これらすべてを美しいケースに詰め込む予定です。
ソフトウェア
コンピューターからトランスミッターにコマンドを送信するために、簡単なスクリプトを作成します。
#!/ usr / bin / env python
「」「
「オン」または「オフ」コマンドを送信機に送信します。
「」「
__future__ import print_function から
輸入 OS
インポートシステム
輸入シリアル
__name__ == '__main__'の場合 :
if len ( sys。argv ) ! = 3 :
print ( "使用法:achtung / dev / ttyXX <ON | OFF>" )
sys 終了 ( 1 )
tty = sys argv [ 1 ]
osで ない 場合 。 パス 存在 ( tty ) :
印刷 ( 「エラー:デバイス '%s'は存在しません」 % tty )
sys 終了 ( 1 )
コマンド= sys argv [ 2 ]
コマンドが ( 'ON' 、 'OFF' )に ない 場合 :
print ( "エラー:不明なコマンド '%s'" % command )
sys 終了 ( 1 )
送信機=シリアル。 シリアル ( tty 、 9600 )
送信機の場合 。 readline ( ) 。 ストリップ ( ) ! = 'achtungの準備' :
印刷 ( 「エラー:デバイスが初期化されていません」 )
sys 終了 ( 1 )
送信機。 書き込み ( "Achtung%sn" %コマンド)
結果=送信機。 readline ( ) 。 ストリップ ( )
結果なら ! = 「OK」 :
印刷 ( 「エラー:デバイスの応答はOKではありません」 )
sys 終了 ( 1 )
スクリプトを機能させるには、依存関係( pyserialモジュール)をインストールする必要があります。
pip install pyserialまず、オン/オフフラッシャーをお楽しみください:
python achtung.py /dev/tty.usbserial-A900FYDU ON python achtung.py /dev/tty.usbserial-A900FYDUオフ
Jenkins CIのアセンブリのステータスを取得するには、 jenkinsapiモジュールを使用するのが最適です。この場合、スクリプトは基本になります。 依存関係のインストール:
pip install jenkinsapiスクリプト自体:
#!/ usr / bin / env python
「」「
Jenkinsジョブのステータスを確認し、ジョブが正常でない場合はアラームを実行します。
「」「
輸入 OS
インポートシステム
輸入 時間
輸入シリアル
ジェンキンサピから 。 ジェンキンス インポート ジェンキンス
ジェンキンサピから 。 例外は JenkinsAPIExceptionをインポートします
URL = 'http://jenkins.example.ru/'
USERNAME = 'jenkins'
パスワード= 「秘密」
JOBS = [ 'build' 、 'test' 、 'lint' ]
TTY = '/dev/tty.usbserial-A900FYDU'
def job_failed ( connect、job_name ) :
「」「
ブール値のジョブステータスを返します(True-成功、False-失敗)。
「」「
job_name が接続されていない 場合 :
真を 返す
last_build = connect [ job_name ] 。 get_last_build ( )
last_buildの場合 。 is_running ( ) :
偽を返す
build_status = last_build。 get_status ( )
build_status in ( 'FAIL' 、 'FAILED' 、 'FAILURE' 、 'ERROR' 、 'REGRESSION' )の場合 :
真を 返す
偽を返す
def send_to_transmitter (デバイス、コマンド) :
「」「
デバイスにコマンドを送信し、エラーが発生すると終了します。
「」「
デバイス。 書き込み ( "Achtung%sn" %コマンド)
結果=デバイス。 readline ( ) 。 ストリップ ( )
結果なら ! = 「OK」 :
印刷 ( 「エラー:デバイスの応答はOKではありません」 )
sys 終了 ( 1 )
__name__ == '__main__'の場合 :
osで ない 場合 。 パス 存在 ( TTY ) :
印刷 ( 「エラー:デバイス '%s'が存在しません」 % TTY )
sys 終了 ( 1 )
試してください :
connect = Jenkins ( URL、ユーザー名、パスワード)
存在する場合 ( jobsのjob_nameのjob_failed ( connect、job_name ) ) :
送信機=シリアル。 シリアル ( TTY、 9600 )
送信機の場合 。 readline ( ) 。 ストリップ ( ) ! = 'achtungの準備' :
印刷 ( 「エラー:デバイスが初期化されていません」 )
sys 終了 ( 1 )
send_to_transmitter (送信機、 「ON」 )
時間 。 寝る ( 5 )
send_to_transmitter (送信機、 「オフ」 )
JenkinsAPIException を除く :
sys 終了 ( 1 )
起動されたスクリプトはJenkinsに接続し、指定されたタスクのステータスを受信し、そのうちの1つが失敗した場合、5秒間点滅ライトをオンにします(これにより、点滅が迷惑にならないようにしますが、ビルドが失敗したことを明確にします)。 このスクリプトは、平日(従業員の勤務時間)の11:00から20:00まで、毎分クラウンで実行されます。夜間または週末にフラッシャーをオンにすることは意味がありません。
もちろん、アセンブリの結果を注ぐことはできませんでしたが、アセンブリが失敗した場合、彼自身がフラッシャーの組み込みを開始するようにJenkinsを構成することができましたが、当社のセキュリティ要件はこの可能性を排除しています:サーバーからネットワークへのオフィスネットワークへの接続は厳しく禁止されています。
利益!
すべてがセットアップされ、動作し、すべての開発者(ビルドをビルドする開発者を除く)が最も適切な瞬間に明るい点滅で喜んでいます。
ソース: https : //github.com/dreadatour/jenkins-achtung
更新 :デバイス操作ビデオ: