Symfoware

Symfowareについての考察blog

C言語でMQTTクライアントを動作させる(paho.mqtt.embedded-c)

MQTTブローカー「mosquitto」をインストール。
Pythonクライアントからイベントの送受信を行ってみました。
MQTTブローカー mosquittoをUbuntu 18.04へインストールする
MQTTクライアントpahoでmosquittoに接続する(Python使用)

MQTTクライアントは各種用意されていますが、
今回はC言語にトライしてみようと思います。
Embedded MQTT C/C++ Client Libraries


ソースの取得



gitリポジトリはこちら。
https://github.com/eclipse/paho.mqtt.embedded-c

ソースを取得します。


$ git clone https://github.com/eclipse/paho.mqtt.embedded-c





クライアントプログラム



プログラムの作成はこちらが非常に参考になりました。
ESP8266にMQTTを実装する (その1)

ダウンロードしたソースの中で必要なのは
MQTTPacket/src
の中身一式です。

912_01.png

「src」を「packet」にリネームして、これから作成するプログラムを配置する
ディレクトリにコピーしました。

912_02.png

もう一箇所
「samples」にある
・pub0sub1.c
・transport.c
・transport.h

をコピーしておきます。

912_03.png

最終的なフォルダ階層はこうなりました。

912_04.png


ここから、「pub0sub1.c」を一箇所編集します。
59行目、「char *host」の指定をMQTTサーバーのIPアドレスに変更。


  1. /*******************************************************************************
  2. * Copyright (c) 2014 IBM Corp.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v1.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. *    http://www.eclipse.org/legal/epl-v10.html
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. *    Ian Craggs - initial API and implementation and/or initial documentation
  15. *    Sergio R. Caprile - clarifications and/or documentation extension
  16. *******************************************************************************/
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include "MQTTPacket.h"
  21. #include "transport.h"
  22. /* This is in order to get an asynchronous signal to stop the sample,
  23. as the code loops waiting for msgs on the subscribed topic.
  24. Your actual code will depend on your hw and approach*/
  25. #include <signal.h>
  26. int toStop = 0;
  27. void cfinish(int sig)
  28. {
  29.     signal(SIGINT, NULL);
  30.     toStop = 1;
  31. }
  32. void stop_init(void)
  33. {
  34.     signal(SIGINT, cfinish);
  35.     signal(SIGTERM, cfinish);
  36. }
  37. /* */
  38. int main(int argc, char *argv[])
  39. {
  40.     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
  41.     int rc = 0;
  42.     int mysock = 0;
  43.     unsigned char buf[200];
  44.     int buflen = sizeof(buf);
  45.     int msgid = 1;
  46.     MQTTString topicString = MQTTString_initializer;
  47.     int req_qos = 0;
  48.     char* payload = "mypayload";
  49.     int payloadlen = strlen(payload);
  50.     int len = 0;
  51.     // MQTTサーバーのIPに変更
  52.     char *host = "192.168.1.102";
  53.     int port = 1883;
  54.     stop_init();
  55.     if (argc > 1)
  56.         host = argv[1];
  57.     if (argc > 2)
  58.         port = atoi(argv[2]);
  59.     mysock = transport_open(host, port);
  60.     if(mysock < 0)
  61.         return mysock;
  62.     printf("Sending to hostname %s port %d\n", host, port);
  63.     data.clientID.cstring = "me";
  64.     data.keepAliveInterval = 20;
  65.     data.cleansession = 1;
  66.     data.username.cstring = "testuser";
  67.     data.password.cstring = "testpassword";
  68.     len = MQTTSerialize_connect(buf, buflen, &data);
  69.     rc = transport_sendPacketBuffer(mysock, buf, len);
  70.     /* wait for connack */
  71.     if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)
  72.     {
  73.         unsigned char sessionPresent, connack_rc;
  74.         if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
  75.         {
  76.             printf("Unable to connect, return code %d\n", connack_rc);
  77.             goto exit;
  78.         }
  79.     }
  80.     else
  81.         goto exit;
  82.     /* subscribe */
  83.     topicString.cstring = "substopic";
  84.     len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);
  85.     rc = transport_sendPacketBuffer(mysock, buf, len);
  86.     if (MQTTPacket_read(buf, buflen, transport_getdata) == SUBACK)     /* wait for suback */
  87.     {
  88.         unsigned short submsgid;
  89.         int subcount;
  90.         int granted_qos;
  91.         rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
  92.         if (granted_qos != 0)
  93.         {
  94.             printf("granted qos != 0, %d\n", granted_qos);
  95.             goto exit;
  96.         }
  97.     }
  98.     else
  99.         goto exit;
  100.     /* loop getting msgs on subscribed topic */
  101.     topicString.cstring = "pubtopic";
  102.     while (!toStop)
  103.     {
  104.         /* transport_getdata() has a built-in 1 second timeout,
  105.         your mileage will vary */
  106.         if (MQTTPacket_read(buf, buflen, transport_getdata) == PUBLISH)
  107.         {
  108.             unsigned char dup;
  109.             int qos;
  110.             unsigned char retained;
  111.             unsigned short msgid;
  112.             int payloadlen_in;
  113.             unsigned char* payload_in;
  114.             int rc;
  115.             MQTTString receivedTopic;
  116.             rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
  117.                     &payload_in, &payloadlen_in, buf, buflen);
  118.             printf("message arrived %.*s\n", payloadlen_in, payload_in);
  119.         }
  120.         printf("publishing reading\n");
  121.         len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, (unsigned char*)payload, payloadlen);
  122.         rc = transport_sendPacketBuffer(mysock, buf, len);
  123.     }
  124.     printf("disconnecting\n");
  125.     len = MQTTSerialize_disconnect(buf, buflen);
  126.     rc = transport_sendPacketBuffer(mysock, buf, len);
  127. exit:
  128.     transport_close(mysock);
  129.     return 0;
  130. }



samples/buildを参考にコンパイル。


$ gcc -Wall -c transport.c -Os -s
$ gcc pub0sub1.c transport.o -I ./packet ./packet/MQTTConnectClient.c ./packet/MQTTSerializePublish.c \
./packet/MQTTPacket.c ./packet/MQTTSubscribeClient.c -o pub0sub1 ./packet/MQTTDeserializePublish.c -Os -s \
./packet/MQTTConnectServer.c ./packet/MQTTSubscribeServer.c ./packet/MQTTUnsubscribeServer.c \
./packet/MQTTUnsubscribeClient.c -ggdb



「pub0sub1」が生成されるので実行します。


$ ./pub0sub1



「substopic」にメッセージを送信するとプログラムで受信。
「pubtopic」を監視すると、プログラムからメッセージが送信されていることが確認できます。

912_05.gif




【参考URL】

ESP8266にMQTTを実装する (その1)
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2018/07/12(木) 22:36:23|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

Ubuntu 18.04にArduino IDEをインストールして、プログラムをArduinoに書き込む

部屋を掃除したら、昔購入したArduinoが出てきました。
Arduinoの開発キットをダウンロードし、サンプルを実行する

懐かしい。久しぶりに触ってみようと思います。
Ubuntu 18.04に開発用のエディタ「Arduino IDE」をインストールしてみます。


Arduino IDE



こちらからダウンロードしました。
https://www.arduino.cc/en/Main/Software

911_01.png

「Linux 64 bits」のリンクをクリックすると、
「arduino-1.8.5-linux64.tar.xz」がダウンロードできました。


インストールはこちらを参考に行います。
https://www.arduino.cc/en/Guide/Linux


xzファイルの解凍はこちらを参考に以下のコマンドを実行。
Linux で tar.xz 形式のファイルを解凍する


$ tar Jxfv arduino-1.8.5-linux64.tar.xz



解凍したディレクトリに移動し、インストールを実行します。


$ cd arduino-1.8.5
$ ./install.sh
Adding desktop shortcut, menu item and file associations for Arduino IDE... done!



インストールと言っても、デスクトップにショートカットを作成するだけのようです。
こんなショートカットがデスクトップに作成されました。

911_02.png

内容は、ファイルを解答したディレクトリの「arduino」へのショートカットです。


[Desktop Entry]
Type=Application
Name=Arduino IDE
GenericName=Arduino IDE
Comment=Open-source electronics prototyping platform
Exec=/home/baranche/dev/arduino-1.8.5/arduino
Icon=arduino-arduinoide
Terminal=false
Categories=Development;IDE;Electronics;
MimeType=text/x-arduino;
Keywords=embedded electronics;electronics;avr;microcontroller;
StartupWMClass=processing-app-Base



デスクトップに作成されたショートカットをダブルクリックすると、初回は警告が表示されます。

911_03.png

「信頼して起動」を選択すると、デスクトップのショートカットにちゃんとアイコンが表示されます。

911_04.png

こんな感じで起動してくれました。

911_05.png



シリアルポートへのアクセス許可



引き続き、こちらを参考に動作環境を整えていきます。
https://www.arduino.cc/en/Guide/Linux

現在のユーザーがシリアルポートにアクセスできるように変更します。
ArduinoをUSBでパソコンに接続した状態でデバイスの情報を表示。

サイトでは、ttyACM*となっていますが旧式のArduinoだからか、
/dev/ttyUSB0で認識されています。


$ ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0 7月 11 23:00 /dev/ttyUSB0



これで現在のユーザーを「dialout」というグループに所属させれば
アクセス権が得られることがわかります。

以下のコマンドで、現在のユーザーをdialoutグループに追加。


$ sudo usermod -a -G dialout `whoami`



この設定、

You will need to log out and log in again for this change to take effect.


とのことなので、一回ログアウト(もしくは再起動)して、設定を反映させます。




サンプルプログラムの書き込み



IDEを解凍したディレクトリの「examples/01.Basics/Blink」に「Blink.ino」という
サンプルがあるので開いてみます。

サンプルをコンパイルして書き込む前に、
[ツール] - [ボード]から接続しているボードの名称を選択。

911_06.png

[ツール] - [シリアルポート]から、「/dev/ttyUSB0」を選択。
※最近のボードだと「/dev/ttyACM0」かも。

911_07.png

エディタのボタンをクリックして書き込みます。

911_08.png

これでLEDがチカチカしてくれました。
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2018/07/12(木) 00:41:26|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

JavaScript 連想配列の先頭に要素を追加する(jQuery UIダイアログのボタンを先頭に追加)

ことの発端は、jQuery UIのモーダルダイアログ。
処理によって、ダイアログに表示するボタンを変更したい。


  1. <html lang="ja">
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>sample</title>
  5. <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
  6. </head>
  7. <body>
  8.     <h3>Dialog</h3>
  9.     <button id="pattern1">はい</button>
  10.     <button id="pattern2">いいえ、はい</button>
  11.     <div id="dialog-form" title="ダイアログサンプル" style="display:none">
  12.         <p>最初にボタンを追加したい!</p>
  13.     </div>
  14.     
  15. <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  16. <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  17. <script>
  18. $(function() {
  19.     
  20.     $('#pattern1').on('click', function() {
  21.         const dialog = $( "#dialog-form" ).dialog({
  22.             buttons: {
  23.                 'はい': () => {
  24.                     dialog.dialog('close');
  25.                 }
  26.             }
  27.         });
  28.     });
  29.     $('#pattern2').on('click', function() {
  30.         const dialog = $( "#dialog-form" ).dialog({
  31.             buttons: {
  32.                 'いいえ': () => {
  33.                     dialog.dialog('close');
  34.                 },
  35.                 'はい': () => {
  36.                     dialog.dialog('close');
  37.                 }
  38.             }
  39.         });
  40.     });
  41.     
  42. })
  43. </script>
  44. </body>



「はい」をクリックしたとき。

910_01.png

「いいえ、はい」をクリックしたとき。

910_02.png


こんな感じで、ダイアログ表示部分を共通化したとします。


  1. <html lang="ja">
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>sample</title>
  5. <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
  6. </head>
  7. <body>
  8.     <h3>Dialog</h3>
  9.     <button id="pattern1">はい</button>
  10.     <button id="pattern2">いいえ、はい</button>
  11.     <div id="dialog-form" title="ダイアログサンプル" style="display:none">
  12.         <p>最初にボタンを追加したい!</p>
  13.     </div>
  14.     
  15. <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  16. <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  17. <script>
  18. $(function() {
  19.     
  20.     $('#pattern1').on('click', function() {
  21.         show_dialog('pattern1');
  22.     });
  23.     $('#pattern2').on('click', function() {
  24.         show_dialog('pattern2');
  25.     });
  26.     const show_dialog = (mode) => {
  27.         let buttons;
  28.         switch(mode) {
  29.             case 'pattern1':
  30.                 buttons = {
  31.                     'はい': () => {
  32.                         dialog.dialog('close');
  33.                     }
  34.                 };
  35.             break;
  36.             case 'pattern2':
  37.                 buttons = {
  38.                     'いいえ': () => {
  39.                         dialog.dialog('close');
  40.                     },
  41.                     'はい': () => {
  42.                         dialog.dialog('close');
  43.                     }
  44.                 };
  45.             break;
  46.         }
  47.         const dialog = $( "#dialog-form" ).dialog({
  48.             buttons: buttons
  49.         });
  50.     };
  51.     
  52. })
  53. </script>
  54. </body>




addFirstというか、連想配列の先頭に要素を追加できれば便利なのに。
※このプログラムは動きません。


  1.     const show_dialog = (mode) => {
  2.         let buttons = {
  3.             'はい': () => {
  4.                 dialog.dialog('close');
  5.             }
  6.         };
  7.         switch(mode) {
  8.             case 'pattern1':
  9.                 // nothing
  10.             break;
  11.             case 'pattern2':
  12.                 buttons.addFirst({
  13.                     'いいえ': () => {
  14.                         dialog.dialog('close');
  15.                     }
  16.                 });
  17.             break;
  18.         }
  19.         const dialog = $( "#dialog-form" ).dialog({
  20.             buttons: buttons
  21.         });
  22.     };






Object.assign()



こちらが参考になりました。
連想配列などのオブジェクトの値をマージするにはObject.assign()を利用する


Object.assign([最初に追加したい配列], [既存の配列])



以下のように修正しました。


  1. <html lang="ja">
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>sample</title>
  5. <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
  6. </head>
  7. <body>
  8.     <h3>Dialog</h3>
  9.     <button id="pattern1">はい</button>
  10.     <button id="pattern2">いいえ、はい</button>
  11.     <div id="dialog-form" title="ダイアログサンプル" style="display:none">
  12.         <p>最初にボタンを追加したい!</p>
  13.     </div>
  14.     
  15. <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  16. <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  17. <script>
  18. $(function() {
  19.     
  20.     $('#pattern1').on('click', function() {
  21.         show_dialog('pattern1');
  22.     });
  23.     $('#pattern2').on('click', function() {
  24.         show_dialog('pattern2');
  25.     });
  26.     const show_dialog = (mode) => {
  27.         let buttons = {
  28.             'はい': () => {
  29.                 dialog.dialog('close');
  30.             }
  31.         };
  32.         switch(mode) {
  33.             case 'pattern1':
  34.                 // nothing
  35.             break;
  36.             case 'pattern2':
  37.                 const firstButton = {
  38.                     'いいえ': () => {
  39.                         dialog.dialog('close');
  40.                     }
  41.                 };
  42.                 buttons = Object.assign(firstButton, buttons);
  43.             break;
  44.         }
  45.         const dialog = $( "#dialog-form" ).dialog({
  46.             buttons: buttons
  47.         });
  48.     };
  49.     
  50. })
  51. </script>
  52. </body>



これで望みどおり、「いいえ」ボタンが先頭に追加できました。




$.extend



Object.assign()、一部のブラウザでは対応されていないようです。
Object.assign()

jQueryの$.extendでも同様の効果が得られるようなので試してみます。


  1. <html lang="ja">
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>sample</title>
  5. <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
  6. </head>
  7. <body>
  8.     <h3>Dialog</h3>
  9.     <button id="pattern1">はい</button>
  10.     <button id="pattern2">いいえ、はい</button>
  11.     <div id="dialog-form" title="ダイアログサンプル" style="display:none">
  12.         <p>最初にボタンを追加したい!</p>
  13.     </div>
  14.     
  15. <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  16. <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  17. <script>
  18. $(function() {
  19.     
  20.     $('#pattern1').on('click', function() {
  21.         show_dialog('pattern1');
  22.     });
  23.     $('#pattern2').on('click', function() {
  24.         show_dialog('pattern2');
  25.     });
  26.     const show_dialog = (mode) => {
  27.         let buttons = {
  28.             'はい': () => {
  29.                 dialog.dialog('close');
  30.             }
  31.         };
  32.         switch(mode) {
  33.             case 'pattern1':
  34.                 // nothing
  35.             break;
  36.             case 'pattern2':
  37.                 const firstButton = {
  38.                     'いいえ': () => {
  39.                         dialog.dialog('close');
  40.                     }
  41.                 };
  42.                 //buttons = Object.assign(firstButton, buttons);
  43.                 buttons = $.extend(firstButton, buttons);
  44.             break;
  45.         }
  46.         const dialog = $( "#dialog-form" ).dialog({
  47.             buttons: buttons
  48.         });
  49.     };
  50.     
  51. })
  52. </script>
  53. </body>



こちらでも、同様の効果が得られました。


関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2018/07/11(水) 22:41:40|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

winetricksによるWineの文字化け(アルファベットが豆腐)を解消

Ubuntu 18.04にWineをインストールし、文字化け(アルファベットが豆腐)を解消する
こちらの手順で文字化けが解消できないパターンがあったので、
別の手法を調べてみました。


winetricks



winetricksをインストールして起動。


$ sudo apt install -y winetricks
$ winetricks



「Select the default wineprefix」を選択してOK。

909_01.png

「Install a font」を選択。

909_02.png

「cjkfonts」にチェックをつけてOK。

909_03.png

インストール中エラーが表示されますが、すべてOKで継続すると、
文字化けせずにちゃんと表示されるようになりました。
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2018/07/08(日) 15:02:09|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

JMeter 4.0 GUI非表示でテストを実行する(Don't use GUI mode for load testing !)

Ubuntu 18.04 + JMEter 4.0で負荷テストを実行してみました。
JMeter 4.0で画像やjs,cssリソースを含めた負荷テストを実行する

GUI起動時、コンソールに気になるメッセージが...


$ ./jmeter.sh
================================================================================
Don't use GUI mode for load testing !, only for Test creation and Test debugging.
For load testing, use NON GUI Mode:
jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
& increase Java Heap to meet your test requirements:
Modify current env variable HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m" in the jmeter batch file
Check : https://jmeter.apache.org/usermanual/best-practices.html
================================================================================



GUIモードはテストプランを作成するときのみ利用して、
実際のテストはコンソールで実行しろとのこと。


コマンドライン実行



こちらを参考にさせていただきました。
【JMeter】負荷テスト実行はGUIから行ってはならない

最低限実行するのに必要なオプションは、


-n (GUI非表示)
-t [テストプランを保存したjmxファイルパス]
-l [結果の出力先]



こんなコマンドで実行してみました。


$ bin/jmeter.sh -n -t 結果を表で表示.jmx -l result.jtl





結果の確認



出力したjtlファイルをGUIのリスナーで読み込むことでテスト結果を確認できます。
例として、結果を表で表示してみます。

「テスト計画」を右クリックして[追加] - [リスナー] - [結果を表で表示]を選択。

908_01.png

「全てのデータをファイルに出力」の「参照」をクリックして、上記で出力した
.jtlファイルを指定します。
「出力」の項目でファイルを読み込めるの、ちょっと罠ですね。気が付きませんでした。

908_02.png

こんな感じでコマンドで実行したテストの結果が確認できます。

908_03.png




htmlでレポート表示



実行後、html形式のレポートを出力するにはこんな感じのコマンドです。
※jtlファイルや-oで指定した出力先フォルダが存在するとエラーになるので、事前に消しておきます。


$ bin/jmeter.sh -n -t 結果を表で表示.jmx -l result.jtl -e -o report



テスト対象のphpに、こんな仕込みを入れて一定の割合で500エラーが発生するようにしておきました。


  1. <?php
  2. $r = rand (1, 10);
  3. if ($r == 1) {
  4.     header('HTTP', true, 500);
  5.     exit();
  6. }
  7. ?>




レポートを出力すると、こんなhtmlが生成されます。

908_04.png

908_05.png


GUI画面より結果を確認しやすいかもしれませんね。



【参考URL】
【JMeter】負荷テスト実行はGUIから行ってはならない
PHPらしいheader関数のシンプルなコード例
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2018/07/05(木) 00:25:18|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
次のページ