Http get request using Arduino and Azure mobile services - azure

I have hooked up my arduino with Azure mobile services and http post request is working fine where I am able to send data from sensor. But when using a http get request to access data from the tables, I am landing up with this data whereas I should be getting a json data in the Serial Window.
X-cache-Lookup: MISS from Webmaster:8080
Here is the code that is on my Arduino. I have no idea where I am wrong.
#include <ArduinoJson.h>
#include <SPI.h>
#include <Ethernet.h>
#define RESPONSE_JSON_DATA_LINENNO 10
// Ethernet shield MAC address (sticker in the back)
byte mac[] = { 0xA4, 0x5D, 0x36, 0x6A, 0xE1, 0xE1 };
int qq=0;
const char* server= "avirup.azure-mobile.net";
const char* table_name= "iottest";
const char* ams_key="rkIEUqVlFrgtmqNeMmaamgUQywwMjE42";
char stat;
EthernetClient client;
char fin='0';
char buffer[64];
int charIndex=0;
StaticJsonBuffer<200> jsonbuffer;
void send_request()
{
Serial.println("\nconnecting...");
if (client.connect(server, 80)) {
Serial.print("sending ");
// GET URI
sprintf(buffer, "GET /tables/%s HTTP/1.1", table_name);
Serial.println(buffer);
client.println(buffer);
// Host header
sprintf(buffer, "Host: %s", server);
client.println(buffer);
// Azure Mobile Services application key
sprintf(buffer, "X-ZUMO-APPLICATION: %s", ams_key);
client.println(buffer);
// JSON content type
client.println("Content-Type: application/json");
//POST body
sprintf(buffer, "", "");
//Content length
client.print("Content-Length: ");
client.println(strlen(buffer));
Serial.print("Content length: ");
Serial.println(strlen(buffer));
// End of headers
client.println();
// Request body
client.println(buffer);
}
else {
Serial.
println("connection failed");
}
}
/*
** Wait for response
*/
void wait_response()
{
while (!client.available()) {
if (!client.connected()) {
return;
}
}
}
/*
** Read the response and dump to serial
*/
// Read the response and dump to serial
void read_response()
{
int jsonStringLength;
int jsonBufferCntr=0;
int numline=RESPONSE_JSON_DATA_LINENNO;
//Ignore the response except for the 10th line
while (client.available()) {
char c = client.read();
if (c == '\n')
{
numline -=1;
}
else
{
if (numline == 0 )
{
//Capture the 10th line in the response
//To do: Could be more deterministic about this:
// Expect certain content, checks and balances etc.
buffer[jsonBufferCntr++] = c;
buffer[jsonBufferCntr] = '\0';
}
}
}
Serial.println("Received:");
Serial.println(buffer);
Serial.println("");
}
/*
** Close the connection
*/
void parse()
{
//char json[] = "{\"id\":\"34CCC60D-15D2-4B53-AB8E-FF3745FDC945\",\"control\":1}";
JsonObject& root = jsonbuffer.parseObject(buffer);
if(!root.success())
{
Serial.println("PARSING FAILED!!!");
return;
}
//fin= root["control"][0];
int f= root["control"][0];
Serial.println("Decoded: ");
Serial.println(f);
}
void end_request()
{
client.stop();
}
/*
** Arduino Setup
*/
void setup()
{
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect.
}
if (Ethernet.begin(mac) == 0) {
Serial.println("ethernet failed");
for (;;) ;
}
// give the Ethernet shield a second to initialize:
delay(1000);
}
/*
** Arduino Loop
*/
void loop()
{
send_request();
wait_response();
read_response();
end_request();
delay(1000);
}

Related

Can't send anything to Azure IoT hub

I am working on a project where I need to send data from an Arduino sensor to Azure IoT hub via MQTT SIMCOM SIM7000E.
The device connects fine however when it comes to sending anything it fails. I think it may be the way I've configured my credentials?
IP: "hub.azure-devices.net"
Client: "Sensor_0001"
Username: "hub.azure-devices.net/Sensor_0001/?api-version=2018-06-30"
Key: "SharedAccessSignature sr=Hub.azure-devices.net%2Fdevices%2FSensor_0001&sig=****"
Topic: "Hub/devices/Sensor_0001/messages/events"
I am very new to this and would appreciate any help or suggestions.
Thanks
#include <Wire.h>
#include <DFRobot_SIM7000.h>
#include "Adafruit_FONA.h"
#include <SoftwareSerial.h>
#define serverIP "EEWHub.azure-devices.net"
#define IOT_CLIENT "EEW_Sensor_0001"
#define IOT_USERNAME "EEWHub.azure-devices.net/EEW_Sensor_0001/?api-version=2018-06-30"
#define IOT_KEY "SharedAccessSignature sr=EEWHub.azure-devices.net%2Fdevices%2FEEW_Sensor_0001&sig=ayW2DcT3YOJGQK6Ch8hEJyNF7MIaT%2BukyfJY03J1Y%2BM%3D&se=1632246687"
#define IOT_TOPIC "devices/EEW_Sensor_0001/messages/events/"
#define PIN_TX 7
#define PIN_RX 8
SoftwareSerial mySerial(PIN_RX, PIN_TX);
DFRobot_SIM7000 sim7000;
void simconnect() {
Serial.begin(115200);
while (!Serial);
sim7000.begin(mySerial);
Serial.println("Turn ON SIM7000......");
if (sim7000.turnON()) { //Turn ON SIM7000
Serial.println("Turn ON !");
}
delay(10000);
Serial.println("Set baud rate......");
while (1) {
if (sim7000.setBaudRate(19200)) { //Set SIM7000 baud rate from 115200 to 19200 reduce the baud rate to avoid distortion
Serial.println("Set baud rate:19200");
break;
} else {
Serial.println("Fail to set baud rate");
delay(1000);
}
}
Serial.println("Attaching service......");
while (1) {
if (sim7000.attachService()) { //Open the connection
Serial.println("Attach service");
break;
} else {
Serial.println("Fail to Attach service");
delay(1000);
}
}
}
void loop() {
String sendData;
Serial.print("Connect to :");
Serial.println(serverIP);
if (sim7000.openNetwork(TCP, serverIP, 8883)) { //Connect to server
Serial.println("Connected !");
} else {
Serial.println("Failed to connect");
return;
}
delay(200);
Serial.print("Connect to : ");
Serial.println(IOT_USERNAME);
if (sim7000.mqttConnect(IOT_CLIENT, IOT_USERNAME, IOT_KEY)) { //MQTT connect request
Serial.println("Connected !");
} else {
Serial.println("Failed to connect");
return;
}
delay(200);
Serial.println("Input data end with CRLF : ");
sendData = readSerial(sendData);
Serial.print("Send data : ");
Serial.print(sendData);
Serial.println(" ......");
if (sim7000.mqttPublish(IOT_TOPIC, sendData)) { //Send data to topic
Serial.println("Send OK");
} else {
Serial.println("Failed to send");
return;
}
delay(200);
Serial.println("Close connection......");
if (sim7000.closeNetwork()) { //Close connection
Serial.println("Close connection !");
} else {
Serial.println("Fail to close connection !");
return;
}
delay(2000);
}
String readSerial(String result) {
int i = 0;
while (1) {
while (Serial.available() > 0) {
char inChar = Serial.read();
if (inChar == '\n') {
result += '\0';
while (Serial.read() >= 0);
return result;
}
if (i == 50) {
Serial.println("The data is too long");
result += '\0';
while (Serial.read() >= 0);
return result;
}
if (inChar != '\r') {
result += inChar;
i++;
}
}
}
}
It looks like your topic is not correct. Try the following:
devices/Sensor_0001/messages/events/
Have a look at this doc for more details.
The following screen snippet shows the MQTTBox client example:
Update:
I have tested connectivity from your example and the following screen shows a result:

Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled

I want to use timer interrupter combined with BLE to transmit in esp32.
I found that an error occurs when the transmission cycle is too fast.
I don't know what caused this error.
Help me plz.............................................................................................
The error
This is my code
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
////////////////////////////////////////////////////////////
#include <BLE2902.h>
#define PERIOD_MS 5
#define BAUD_RATE 115200
#define BLE_WR_EN 0x5A
#define BLE_WR_DIS 0x55
#define SERVICE_UUID "0000ffe0-0000-1000-8000-00805f9b34fb"
#define CHARACTERISTIC_UUID_RX "0000ffe2-0000-1000-8000-00805f9b34fb"
#define CHARACTERISTIC_UUID_TX "0000ffe1-0000-1000-8000-00805f9b34fb"
int PERIOD_US=PERIOD_MS*1000;
/* create a hardware timer */
hw_timer_t * timer = NULL;
/* LED pin */
int led = 2;
/* LED state */
volatile byte state = LOW;
int i=0;
BLEServer *pServer;
BLEService *pService;
BLECharacteristic *pCharacteristic;
void IRAM_ATTR onTimer(){
//state = !state;
if(i<700){
i++;
}
else{
i=0;
}
//Serial.println(state);
char txString[8];
dtostrf(i, 1, 2, txString);
pCharacteristic->setValue(txString);
pCharacteristic->notify();
std::string txValue=pCharacteristic->getValue();
Serial.print("txValue:");
Serial.println(txValue.c_str());
//digitalWrite(led, state);
}
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
Serial.println("********************************");
Serial.println("Connected");
Serial.println("********************************");
timerAlarmEnable(timer);
};
void onDisconnect(BLEServer* pServer) {
Serial.println("********************************");
Serial.println("Disconnected");
Serial.println("********************************");
timerAlarmDisable(timer);
//delay(1000);
///*
// Start the service
//pService->start();
// Start advertising
//pServer->getAdvertising()->start();
pServer->startAdvertising();
//*/
//ESP.restart();
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
std::string EN="Z";
std::string DIS="U";
Serial.print("rxValue:");
Serial.println(rxValue.c_str());
/*
//Serial.println(getvalue);
if (rxValue==EN ) {
//g_Timer.enable(g_TimerId);
timerAlarmEnable(timer);
digitalWrite(LED, HIGH);
}
else if (rxValue==DIS) {
//g_Timer.disable(g_TimerId);
timerAlarmDisable(timer);
//data_count = 0;
digitalWrite(LED, LOW);
}
*/
}
};
void setup() {
Serial.begin(115200);
Serial.begin(BAUD_RATE);
////////////////////////////////////////
Serial.println("Starting BLE Server!");
BLEDevice::init("ESP32-INTERRUT-Server");
/////////////////////////////////////////////////////////////////////////////////////
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_READ|
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
////////////////////////////////////////////////////////////////////
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, PERIOD_US, true);
timerAlarmDisable(timer);
}
void loop() {
}

ESP8266 is not getting connected to my deployed websocket on heroku

I have deployed a nodejs websocket on heroku. But my ESP8266 cannot get connected to that websocket. Before deploying that websocket on heroku, i tried it out locally and it worked pretty well. ESP8266 also got connected to it without any error. Then I made some changes in nodejs socket (before deploying) in order to run it on heroku. i just don't understand what's wrong with this esp8266 code
ESP8266's Code
#include <ESP8266WiFi.h>
#include <WebSocketClient.h>
boolean handshakeFailed = 0;
String data = "";
char path[] = "/"; //identifier of this device
const char *ssid = ""; //<-------------------this was entered correctly. Wifi connection was successful. websocket connection got failed
const char *password = ""; // <-------------------this was entered correctly. Wifi connection was successful. websocket connection got failed
char *host = "example.herokuapp.com"; //replace this ip address with the ip address of your Node.Js server
const int espport = 3000;
WebSocketClient webSocketClient;
unsigned long previousMillis = 0;
unsigned long currentMillis;
unsigned long interval = 300; //interval for sending data to the websocket server in ms
// Use WiFiClient class to create TCP connections
WiFiClient client;
void setup()
{
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(1000);
wsconnect();
// wifi_set_sleep_type(LIGHT_SLEEP_T);
}
void loop()
{
if (client.connected())
{
currentMillis = millis();
webSocketClient.getData(data);
if (data.length() > 0)
{
Serial.println(data);
//*************send log data to server in certain interval************************************
//currentMillis=millis();
if (abs(currentMillis - previousMillis) >= interval)
{
previousMillis = currentMillis;
data = (String)analogRead(A0); //read adc values, this will give random value, since no sensor is connected.
//For this project we are pretending that these random values are sensor values
webSocketClient.sendData(data); //send sensor data to websocket server
}
}
else
{
}
delay(5);
}
}
void wsconnect()
{
// Connect to the websocket server
if (client.connect(host, espport))
{
Serial.println("WebSocket Connected");
}
else
{
Serial.println("Connection failed.");
delay(1000);
if (handshakeFailed)
{
handshakeFailed = 0;
ESP.restart();
}
handshakeFailed = 1;
}
// Handshake with the server
webSocketClient.path = path;
webSocketClient.host = host;
if (webSocketClient.handshake(client))
{
Serial.println("Handshake successful");
}
else
{
Serial.println("Handshake failed.");
delay(4000);
if (handshakeFailed)
{
handshakeFailed = 0;
ESP.restart();
}
handshakeFailed = 1;
}
}

libuv based server crash when there are two connections back to back

Doing some research on high performance TCP server (not necessarily for HTTP) for testing purpose. Followed some sample code and created a libuv based TCP server, however the following sample code will crash with error SIGPIPE on the line uv_write(req, stream, buffer, 1, on_write);. Here is the console output:
client=0x562529924700
1writing to 0x562529924700
2writing to 0x562529924700
wrote.
1writing to 0x562529924700
Note that the tcp client closes the first tcp connection with TCP RESET. Wireshark shows that the TCP client has established the second tcp connection and sent the request, but the tcp server somehow didn't print something similar to the line client=0x562529924700 to indicate that it has accept the second connection.
Any ideas would be appreciated.
Here is the server code
//from https://gist.github.com/Jxck/4305806
// https://nikhilm.github.io/uvbook/networking.html
//api guide http://docs.libuv.org/en/v1.x/
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
#include <string.h>
#include <unistd.h>
#define DEFAULT_PORT 8080
#define DEFAULT_BACKLOG 1000
uv_loop_t *loop;
int cnt = 0;
char *str = "HTTP/1.1 200 Ok\r\nContent-Length: 7\r\n\r\n%07d\n";
void on_write(uv_write_t* req, int status)
{
if (status) {
perror( "uv_write error ");
return;
}
printf("wrote.\n");
free(req);
//uv_close((uv_handle_t*)req->handle, on_close);
}
void write2(uv_stream_t* stream, char *data, int len2) {
uv_buf_t buffer[] = {
{.base = data, .len = len2}
};
uv_write_t *req = malloc(sizeof(uv_write_t));
printf("1writing to %p\n", stream);
uv_write(req, stream, buffer, 1, on_write);
printf("2writing to %p\n", stream);
}
void on_close(uv_handle_t* handle)
{
//printf("closed.");
}
void echo_read(uv_stream_t *sock, ssize_t nread, const uv_buf_t *buf) {
if (nread == -1) {
fprintf(stderr, "error echo_read");
return;
} else if (nread == 0) {
uv_close((uv_handle_t*)sock, on_close);
return;
}
char respMsg[52];
sprintf(respMsg, str, cnt++);
//snprintf(&respMsg[41], 6,"%6d", cnt++);
write2(sock, respMsg, strlen(respMsg));
//printf("result: %s\n", buf->base);
}
static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
void on_new_connection(uv_stream_t *server, int status) {
if (status < 0) {
fprintf(stderr, "New connection error %s\n", uv_strerror(status));
// error!
return;
}
uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
printf("client=%p\n", client);
uv_tcp_init(loop, client);
if (uv_accept(server, (uv_stream_t*) client) == 0) {
uv_read_start((uv_stream_t*) client, my_alloc_cb, echo_read);
}
else {
printf("failed to accept\n");
uv_close((uv_handle_t*) client, NULL);
}
}
int main() {
loop = uv_default_loop();
uv_tcp_t server;
uv_tcp_init(loop, &server);
struct sockaddr_in addr;
uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr);
int r;
r = uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection);
if (r) {
fprintf(stderr, "Listen error %s\n", uv_strerror(r));
return 1;
}
return uv_run(loop, UV_RUN_DEFAULT);
}
Turned out the issue is on echo_read(). When the TCP connection is terminated with tcp reset, nread is not -1, it's some negative number (-4095 in my case).
Was able to take care of it using nread < 0 instead of nread == -1.
void echo_read(uv_stream_t *sock, ssize_t nread, const uv_buf_t *buf) {
if (nread == -1) {
fprintf(stderr, "error echo_read");
return;
} else if (nread == 0) {
uv_close((uv_handle_t*)sock, on_close);
return;
}

bluez pairing before exchange

I'm using code from An Introduction to Bluetooth Programming ► Chapter 4. Bluetooth programming in C with BlueZ4.2. ► RFCOMM sockets to send messages between two Raspberry Pi.
However, if I don't make the pairing between two devices through the bluetoothctl, I can't use the client because it gives me error:
uh oh: Invalid exchange.
Can you give me some hints on how can I make the pair through the C code? I need to use this "automatically" without need to pairing through the bluetoothctl before the C code.
Before getting into my answer, I am not sure how to achieve this using "libbluetooth" API's. But my below answer is based on DBUS API using GDBUS. This should most likely work with any recent bluez (with bluetoothd) running.
Note, with Bluez5 it's recommended to use DBUS API's.
To brief, you need to develop an Agent which accepts the Pairing request automatically, assuming "Confirmation" agent here. Please refer agent capabilities here.
With recent bluez version (atleast 5.47+), we have a new API "ConnectDevice" which can be used to connect device without scanning/discovery. From your question, I understand that you are trying to communicate between two RPi's, so you can find the BT address for both the bluetooth controllers. With BT address in places,
/*
* bluez_adapter_connect.c - Connect with device without StartDiscovery
* - This example registers an agen with NoInputOutput capability for the purpose of
* auto pairing
* - Use ConnectDevice method to connect with device using provided MAC address
* - Usual signal subscription to get the details of the connected device
* - Introduced new signal handler to exit the program gracefully
*
* Note: As "ConnectDevice" is new API and in experimental state (but mostly stable)
* one need to use "-E" option when starting "bluetoothd". Systems running systemd can
* edit /lib/systemd/system/bluetooth.service in ExecStart option
*
* When this API is useful?
* - When you already have the MAC address of end bluetooth Device to connect with, then
* you don't need to scan for the device (with or without filter) and connect it.
* - StartDiscovery + Pair + Connect => ConnectDevice
*
* How you will have MAC address before scanning?
* - When you have other communication (wired or wireless) medium to exchange the MAC address
* - For example, NFC OOB can be used to exchange the MAC address
* - Testing Bluetooth with same device (MAC address known)
*
* - Here Agent capability is registered as "NoInputOutput" for experimental purpose only, in
* real world scenario, Pair + Connect involves real Agents.
* - Also note, bluez_agent_call_method and bluez_adapter_call_method are two different methods doing
* the same work with difference in interface name and object path. This exist just to make the
* understanding more clear.
*
* gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/bluez_adapter_connect ./bluez_adapter_connect.c `pkg-config --libs glib-2.0 gio-2.0`
*/
#include <glib.h>
#include <gio/gio.h>
#include <signal.h>
GMainLoop *loop;
GDBusConnection *con;
static void bluez_property_value(const gchar *key, GVariant *value)
{
const gchar *type = g_variant_get_type_string(value);
g_print("\t%s : ", key);
switch(*type) {
case 'o':
case 's':
g_print("%s\n", g_variant_get_string(value, NULL));
break;
case 'b':
g_print("%d\n", g_variant_get_boolean(value));
break;
case 'u':
g_print("%d\n", g_variant_get_uint32(value));
break;
case 'a':
/* TODO Handling only 'as', but not array of dicts */
if(g_strcmp0(type, "as"))
break;
g_print("\n");
const gchar *uuid;
GVariantIter i;
g_variant_iter_init(&i, value);
while(g_variant_iter_next(&i, "s", &uuid))
g_print("\t\t%s\n", uuid);
break;
default:
g_print("Other\n");
break;
}
}
typedef void (*method_cb_t)(GObject *, GAsyncResult *, gpointer);
static int bluez_adapter_call_method(const char *method, GVariant *param, method_cb_t method_cb)
{
g_dbus_connection_call(con,
"org.bluez",
/* TODO Find the adapter path runtime */
"/org/bluez/hci0",
"org.bluez.Adapter1",
method,
param,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
method_cb,
(void *)method);
return 0;
}
static void bluez_result_async_cb(GObject *con,
GAsyncResult *res,
gpointer data)
{
const gchar *key = (gchar *)data;
GVariant *result = NULL;
GError *error = NULL;
result = g_dbus_connection_call_finish((GDBusConnection *)con, res, &error);
if(error != NULL) {
g_print("Unable to get result: %s\n", error->message);
return;
}
if(result) {
result = g_variant_get_child_value(result, 0);
bluez_property_value(key, result);
}
g_variant_unref(result);
}
static void bluez_device_appeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
(void)user_data;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
GVariant *properties;
g_variant_get(parameters, "(&oa{sa{sv}})", &object, &interfaces);
while(g_variant_iter_next(interfaces, "{&s#a{sv}}", &interface_name, &properties)) {
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device")) {
g_print("[ %s ]\n", object);
const gchar *property_name;
GVariantIter i;
GVariant *prop_val;
g_variant_iter_init(&i, properties);
while(g_variant_iter_next(&i, "{&sv}", &property_name, &prop_val))
bluez_property_value(property_name, prop_val);
g_variant_unref(prop_val);
}
g_variant_unref(properties);
}
return;
}
#define BT_ADDRESS_STRING_SIZE 18
static void bluez_device_disappeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
char address[BT_ADDRESS_STRING_SIZE] = {'\0'};
g_variant_get(parameters, "(&oas)", &object, &interfaces);
while(g_variant_iter_next(interfaces, "s", &interface_name)) {
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device")) {
int i;
char *tmp = g_strstr_len(object, -1, "dev_") + 4;
for(i = 0; *tmp != '\0'; i++, tmp++) {
if(*tmp == '_') {
address[i] = ':';
continue;
}
address[i] = *tmp;
}
g_print("\nDevice %s removed\n", address);
g_main_loop_quit((GMainLoop *)user_data);
}
}
return;
}
static void bluez_signal_adapter_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
void *userdata)
{
(void)conn;
(void)sender;
(void)path;
(void)interface;
(void)userdata;
GVariantIter *properties = NULL;
GVariantIter *unknown = NULL;
const char *iface;
const char *key;
GVariant *value = NULL;
const gchar *signature = g_variant_get_type_string(params);
if(strcmp(signature, "(sa{sv}as)") != 0) {
g_print("Invalid signature for %s: %s != %s", signal, signature, "(sa{sv}as)");
goto done;
}
g_variant_get(params, "(&sa{sv}as)", &iface, &properties, &unknown);
while(g_variant_iter_next(properties, "{&sv}", &key, &value)) {
if(!g_strcmp0(key, "Powered")) {
if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
g_print("Invalid argument type for %s: %s != %s", key,
g_variant_get_type_string(value), "b");
goto done;
}
g_print("Adapter is Powered \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
}
if(!g_strcmp0(key, "Discovering")) {
if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
g_print("Invalid argument type for %s: %s != %s", key,
g_variant_get_type_string(value), "b");
goto done;
}
g_print("Adapter scan \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
}
}
done:
if(properties != NULL)
g_variant_iter_free(properties);
if(value != NULL)
g_variant_unref(value);
}
static int bluez_adapter_set_property(const char *prop, GVariant *value)
{
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_sync(con,
"org.bluez",
"/org/bluez/hci0",
"org.freedesktop.DBus.Properties",
"Set",
g_variant_new("(ssv)", "org.bluez.Adapter1", prop, value),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL)
return 1;
g_variant_unref(result);
return 0;
}
static int bluez_adapter_connect_device(char **argv)
{
int rc;
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_VARDICT);
g_variant_builder_add(b, "{sv}", "Address", g_variant_new_string(argv[1]));
GVariant *device_dict = g_variant_builder_end(b);
g_variant_builder_unref(b);
rc = bluez_adapter_call_method("ConnectDevice",
g_variant_new_tuple(&device_dict, 1),
bluez_result_async_cb);
if(rc) {
g_print("Not able to call ConnectDevice\n");
return 1;
}
return 0;
}
#define AGENT_PATH "/org/bluez/AutoPinAgent"
static int bluez_agent_call_method(const gchar *method, GVariant *param)
{
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_sync(con,
"org.bluez",
"/org/bluez",
"org.bluez.AgentManager1",
method,
param,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL) {
g_print("Register %s: %s\n", AGENT_PATH, error->message);
return 1;
}
g_variant_unref(result);
return 0;
}
static int bluez_register_autopair_agent(void)
{
int rc;
rc = bluez_agent_call_method("RegisterAgent", g_variant_new("(os)", AGENT_PATH, "NoInputNoOutput"));
if(rc)
return 1;
rc = bluez_agent_call_method("RequestDefaultAgent", g_variant_new("(o)", AGENT_PATH));
if(rc) {
bluez_agent_call_method("UnregisterAgent", g_variant_new("(o)", AGENT_PATH));
return 1;
}
return 0;
}
static void cleanup_handler(int signo)
{
if (signo == SIGINT) {
g_print("received SIGINT\n");
g_main_loop_quit(loop);
}
}
int main(int argc, char **argv)
{
int rc;
guint prop_changed;
guint iface_added;
guint iface_removed;
if(signal(SIGINT, cleanup_handler) == SIG_ERR)
g_print("can't catch SIGINT\n");
con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
if(con == NULL) {
g_print("Not able to get connection to system bus\n");
return 1;
}
loop = g_main_loop_new(NULL, FALSE);
prop_changed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Adapter1",
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_signal_adapter_changed,
NULL,
NULL);
iface_added = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesAdded",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_appeared,
loop,
NULL);
iface_removed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesRemoved",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_disappeared,
loop,
NULL);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", TRUE));
if(rc) {
g_print("Not able to enable the adapter\n");
goto fail;
}
rc = bluez_register_autopair_agent();
if(rc) {
g_print("Not able to register default autopair agent\n");
goto fail;
}
if(argc == 2) {
rc = bluez_adapter_connect_device(argv);
if(rc)
goto fail;
}
g_main_loop_run(loop);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", FALSE));
if(rc)
g_print("Not able to disable the adapter\n");
fail:
g_dbus_connection_signal_unsubscribe(con, prop_changed);
g_dbus_connection_signal_unsubscribe(con, iface_added);
g_dbus_connection_signal_unsubscribe(con, iface_removed);
g_object_unref(con);
return 0;
}
you should be able to use the above program to connect the device. Here in this example, the agent is registered as "NoInputOutput" capability, something like bluetooth headphones, so that no pairing response is required.
But you should modify this example to client side (assuming this example going to run in RPi 1 as server, modify this to accept request in client side RPi 2).
You can find the detailed explanation about this example here and also some relevant GDBUS based examples here.

Resources