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. | 編集

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. | 編集

Amazon FreeRTOS Windows SimulatorをVisual Studio 2017 Communityで動かす

Amazon FreeRTOS Windows SimulatorをVisual Studio 2017 Communityで
動作させるまでのメモです。

こちらを参考にさせていただきました。
Amazon FreeRTOS Windows Simulator のセットアップメモ

なお、こちらの証明書の設定が完了した環境で試しています。
AWS IoTにPythonでMQTTイベントの送信、受信するまで - AWS IoT Device SDK for Python
事前に証明書の設定は完了しているものとします。



Amazon FreeRTOSのダウンロード



AWS IoTの管理コンソールの「ソフトウェア」を選択。
「Amazon FreeRTOS デバイスソフトウェア」のダウンロードの設定をクリックします。

906_01.png


「事前定義済み Connect to AWS IoT - Windows」をダウンロードし、解凍します。

906_02.png



WinPcap



ビルド&実行するには「WinPcap」をインストールする必要があります。
こちらからダウンロードして、インストールしておきました。
https://www.winpcap.org/



SDKバージョンの変更



Visual StudioでAmazonFreeRTOS\demos\pc\windows\visual_studio\aws_demos.sln
を開き、ビルドしてみるとこんなエラーになります。


エラー    MSB8036
Windows SDK バージョン 10.0.15063.0 が見つかりませんでした。
必要なバージョンの Windows SDK をインストールするか、プロジェクト プロパティ ページで SDK バージョンを変更するか、
ソリューションを右クリックして [ソリューションの再ターゲット] を選択してください。



ソリューションエクスプローラーで「aws_demos」を右クリックしてプロパティを表示。
「全般」の「Windows SDKバージョン」を変更します。

10.0.15063.0となっている箇所を...

906_03.png

コンボボックスの中の選択肢「10.0.17134.0」に変更しました。

906_04.png



各種設定の変更



ビルドが通るようになったら、とりあえず実行してみます。

906_05.png

ネットワークの一覧が表示されます。
例では1つですが、ネットワークアダプターを認識しているインターフェース番号を控えておきます。

・AmazonFreeRTOS\demos\pc\windows\common\config_files\FreeRTOSConfig.h

FreeRTOSConfig.hの「configNETWORK_INTERFACE_TO_USE」を
先程調べたインターフェース番号に変更します。


  1. #define configNETWORK_INTERFACE_TO_USE     1L




・AmazonFreeRTOS\demos\common\include\aws_clientcredential.h

static const char clientcredentialMQTT_BROKER_ENDPOINT[]に
指定するエンドポイントを変更します。


  1. static const char clientcredentialMQTT_BROKER_ENDPOINT[] = "xxxxxxxxxx.iot.ap-northeast-1.amazonaws.com";



エンドポイントはIoTコンソールの「設定」で確認できます。
※参考
AWS IoTにPythonでMQTTイベントの送信、受信するまで - AWS IoT Device SDK for Python


・AmazonFreeRTOS\demos\common\include\aws_clientcredential_keys.h

aws_clientcredential_keys.hを生成するため、ブラウザで以下のパスのhtmlを開きます。
AmazonFreeRTOS\demos\common\devmode_key_provisioning\CertificateConfigurationTool\CertificateConfigurator.html

906_06.png

AWS IoTにPythonでMQTTイベントの送信、受信するまで - AWS IoT Device SDK for Python
こちらで作成した、

「このモノの証明書」「プライベートキー」
・XXXXXXXXXX-certificate.pem.crt
・XXXXXXXXXX-private.pem.key

をそれぞれ指定し、「Generate」をクリックします。

できあがったaws_clientcredential_keys.hで、
AmazonFreeRTOS\demos\common\include\aws_clientcredential_keys.h
を上書きします。

これで準備完了です。


テスト



IoT管理コンソールで「freertos/demos/echo」トピックを監視します。

906_07.png

906_08.png


プログラムを実行。

906_09.png

ぞくぞくとメッセージが送信されてきます。

906_10.png

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

  1. 2018/07/02(月) 23:21:57|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

DynamoDB 条件付きでデータを更新する

DynamoDBの機能を試しています。
DynamoDB LocalにPython(boto3)でテーブルの作成、データの登録
DynamoDB データのインクリメント、デクリメント(アトミックカウンター)

今回は、SQLで言うところのwhere句を指定してのデータ更新を試してみます。


ステップ 3.5: 項目を更新する (条件付き)



こちらを参考にしています。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/GettingStarted.Python.03.html

データは、前回作成したものをそのまま流用しました。
DynamoDB データのインクリメント、デクリメント(アトミックカウンター)

サンプルを見様見真似で、メンバーが3名より多い場合、データのの「defeat_count」を
10で更新してみます。

キーを指定せず更新できると思っていたのですが、Keyは必須のようで思い通りの操作になりませんでした。
(本当は全件更新したかった)


  1. # -*- coding:utf-8 -*-
  2. import boto3
  3. # 接続
  4. dynamodb = boto3.resource(
  5.     'dynamodb',
  6.     region_name='ap-northeast-1.',
  7.     endpoint_url="http://192.168.1.102:8000",
  8.     aws_access_key_id='ACCESS_ID',
  9.     aws_secret_access_key='ACCESS_KEY'
  10. )
  11. # テーブル取得
  12. table = dynamodb.Table('Sample')
  13. # データ更新
  14. response = table.update_item(
  15.     Key={
  16.         'id':1,
  17.         'team': 'あんこう',
  18.     },
  19.     UpdateExpression='set defeat_count = :defeat_count',
  20.     ConditionExpression="size(members) > :num",
  21.     ExpressionAttributeValues={
  22.         ':defeat_count': 10,
  23.         ':num': 3
  24.     },
  25.     ReturnValues='UPDATED_NEW'
  26. )
  27. print(response)





リスト項目の削除



setでデータを更新しましたが、removeでリストの項目の削除が行なえます。
更新の式には、他にもaddやdeleteがあります。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html

membersの最初の項目を削除してみます。


  1. # -*- coding:utf-8 -*-
  2. import boto3
  3. # 接続
  4. dynamodb = boto3.resource(
  5.     'dynamodb',
  6.     region_name='ap-northeast-1.',
  7.     endpoint_url="http://192.168.1.102:8000",
  8.     aws_access_key_id='ACCESS_ID',
  9.     aws_secret_access_key='ACCESS_KEY'
  10. )
  11. # テーブル取得
  12. table = dynamodb.Table('Sample')
  13. # データ更新
  14. response = table.update_item(
  15.     Key={
  16.         'id':1,
  17.         'team': 'あんこう',
  18.     },
  19.     UpdateExpression='remove members[0]',
  20.     ConditionExpression="size(members) > :num",
  21.     ExpressionAttributeValues={
  22.         ':num': 3
  23.     },
  24.     ReturnValues='UPDATED_NEW'
  25. )
  26. print(response)




最初の実行


$ python3 sample.py
{'Attributes': {'members': ['武部 沙織', '五十鈴 華', '秋山 優花里', '冷泉 麻子']},



2回目の実行


$ python3 sample.py
{'Attributes': {'members': ['五十鈴 華', '秋山 優花里', '冷泉 麻子']},



もう一度実行すると、条件に合致するデータがないのでエラーになります。


$ python3 sample.py
botocore.errorfactory.ConditionalCheckFailedException:
An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed






リスト項目の追加



削除したメンバーを戻しておきます。
リストに項目を追加するには「list_append」を使用します。


  1. # -*- coding:utf-8 -*-
  2. import boto3
  3. # 接続
  4. dynamodb = boto3.resource(
  5.     'dynamodb',
  6.     region_name='ap-northeast-1.',
  7.     endpoint_url="http://192.168.1.102:8000",
  8.     aws_access_key_id='ACCESS_ID',
  9.     aws_secret_access_key='ACCESS_KEY'
  10. )
  11. # テーブル取得
  12. table = dynamodb.Table('Sample')
  13. # データ更新
  14. response = table.update_item(
  15.     Key={
  16.         'id':1,
  17.         'team': 'あんこう',
  18.     },
  19.     UpdateExpression='set members = list_append(members, :append_members)',
  20.     ExpressionAttributeValues={
  21.         ':append_members': ['西住 みほ', '武部 沙織']
  22.     },
  23.     ReturnValues='UPDATED_NEW'
  24. )
  25. print(response)




実行結果


$ python3 sample.py
{'Attributes': {'members': ['五十鈴 華', '秋山 優花里', '冷泉 麻子', '西住 みほ', '武部 沙織']},



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

  1. 2018/06/25(月) 23:02:13|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
次のページ