DeviceClient.GetTwinAsync() returns null? - azure-iot-hub

I've created an IotHub, added a device, created a UWP app which uses the DeviceClient to successfully connect to the hub.
I can send telemetry as expected, and see the results in the Device Explorer.
However, when I try to fetch the device twin, I'm returned a null.
var deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Amqp);
var twin = await deviceClient.GetTwinAsync(); // <<<< returns null
Are there any common scenarios that might cause this? Such as creating the IoTHub & device before Twin's were released. Or, not having set any desired properties before hand? Or, using the wrong shared access key? (etc.)
-John

SOLUTION: Twin capabilities requires the MQTT protocol, I was using AMQP.
I'm sure there is a mention of this buried somewhere, but after spinning on this for hours I can safely say it wasn't obvious.
On a more practical note: it would probably be helpful to throw an exception in the GetTwinAsync() method, if it is called on a connection that is not capable of supporting Twin.
Hopefully this post will help the next person.
-John

Related

ESP-IDF wifi event loop keeps receiving SYSTEM_EVENT_STA_WPS_ER_PIN even after code rollback

I have been working on a project using the ESP32 with the ESP-IDF that will check it's NVS memory for wifi credentials before starting the network stack. If it has said credentials, it will connect to the wifi network in STA mode, if it lacks them, it will launch as it's own AP to allow the user to send it the credentials over HTTP.
After manually putting my test credentials into NVS, I started working on the AP code. Once all the AP code and logic was complete, I manually wiped the flash memory with esptool to force the board to launch in that mode. Doing so worked fine, and I was able to send it the updated credentials over HTTP.
At this point, the board attempted to connect as STA upon reset, however, the SYSTEM_EVENT_STA_WPS_ER_PIN event kept being caught by the wifi event loop. The board has since only experienced this event and has been completely unable to connect to wifi since. To make matters stranger, even after rolling back to a previous version with git, the problem still persists.
main.c
void app_main() {
// Start NVS
initNVS();
// Init Wifi Controller
initWifiController();
// Get Credentials to send to wifi
Creds creds = getCreds();
// Start wifi in STA mode with gathered creds
beginWifi(creds);
initializePins();
initializeTimers();
}
wifiController.c
void initWifiController(){
// * NVS must be initialized before wifi work can be done
// Handle when connected to the network
connectionSemaphore = xSemaphoreCreateBinary();
// Begin network stack
ESP_ERROR_CHECK(esp_netif_init());
// Create event loop for handling callbacks
ESP_ERROR_CHECK(esp_event_loop_create_default());
}
void beginWifi(Creds creds){
if(creds.status == ESP_OK){
ESP_LOGI(TAG, "Connection credentials have been found, connecting to network");
connectSTA(creds);
}
else if(creds.status == ESP_ERR_NVS_NOT_FOUND){
ESP_LOGW(TAG, "Missing credentials, starting as AP");
connectAP();
}
else{
ESP_LOGE(TAG, "ESP failed with error %s, not starting wifi", esp_err_to_name(creds.status));
}
void connectSTA(Creds creds){
ESP_LOGI(TAG, "Attempting to connect to wifi with following creds: %s | %s", creds.ssid, creds.pass);
// Set netif to sta
esp_netif_create_default_wifi_sta();
// Prepare and initialize wifi_init_config_t
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
// Register tracked events for event_handler
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL));
// TODO: Check if this can be used to avoid havng to use NVS manually
esp_wifi_set_storage(WIFI_STORAGE_RAM);
// Config struct for wifi details
wifi_config_t wifi_config = {};
// Copy casted info into wifi_config
// * https://www.esp32.com/viewtopic.php?f=13&t=14611
// * See above link for details on this
strcpy((char *)wifi_config.sta.ssid, creds.ssid);
strcpy((char *)wifi_config.sta.password, creds.pass);
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
ESP_ERROR_CHECK(esp_wifi_start());
// ? Is this required to avoid a memory leak?
free(creds.pass);
free(creds.ssid);
}
void connectAP(){
// ? How important is it that these be called in this order?
ESP_LOGI(TAG, "Starting in AP Mode");
esp_netif_create_default_wifi_ap();
// TODO: maybe move this creation to initWifiController to avoid making it twice
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
// TODO: Consider moving this to init Wifi Controller to avoid running it twice as well
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
// Configuration for AP
wifi_config_t wifi_config = {
.ap = {
.ssid = "Grow System",
.password = "Password",
.ssid_len = strlen("Grow System"),
.max_connection = 4,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
}
};
// TODO: Enable password support on AP configuration
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Wifi connectAP finished");
registerEndPoints();
}
The code essentially checks NVS for the credentials, if it finds them both it returns a struct containing both of them as well as ESP_OK. If one of them was not found, the struct instead contains ESP_ERR_NVS_NOT_FOUND. wifiController.c then receives this creds struct and calls beginWifi() which then either calls connectSTA() or connectAP() based on the status of the struct. When the credentials are present, connectSTA() is called, but for unknown reasons the event loop consistently only receives the SYSTEM_EVENT_STA_WPS_ER_PIN event. As I mentioned earlier, even after rolling my code back to a version that did not have the connectAP() function, this behavior persists.
Because of this, I have a hunch that the issue may be related to when I wiped the flash manually, as opposed to the code.
The header file contains the following line in it's typedef to define this event.
SYSTEM_EVENT_STA_WPS_ER_PIN, /*!< ESP32 station wps pin code in enrollee mode */
I do not know what that means, as I have not intentionally included anything regarding wps in this project.
So far my research hasn't returned anything incredibly useful, so if anyone has any ideas what SYSTEM_EVENT_STA_WPS_ER_PIN is or what could be causing my issue, I would be very appreciative. If you think that anymore detail would be useful to solve this issue, please let me know and I will be more than happy to provide it.
Useful to solve the problem.
I'm in the proces of learning to use the ESP32 wifi, read your message checked, the ESP-idf and esp-32 technical manual not much info there I found this URI
https://www.wi-fi.org/downloads-public/Wi-Fi_Protected_Setup_Best_Practices_v2.0.2.pdf/8188
Kind regards
Update: check the sdkconfig file in your projectmap against the one in the example map for wifi config settings.
I have been digging into this issue for several days now and I have not found the root cause but have managed to discovery a workaround and some details about the issue. the SYSTEM_EVENT_STA_WPS_ER_PIN event that kept arising actually is caused by the chip trying to use WPS Enrolle Pin mode to connect to the router. Supposedly this generates an eight digit long pin that can be put into your router which should allow it to connect. I really do not know why it was doing this, but I believe it may have had something to do with how I had AP mode set up. My primary confusion now is why rolling back the code did not fix it.
For the "workaround" I found that flashing Espressif's example STA wifi connection code managed to solve it. The chip properly connected to my network once it was flashed, and I was able to reflash my own code without any issues arriving. This seems extremely strange to me, so part of me thinks that maybe the chip just couldn't connect to my network for some reason and an edge case in the code caused it to go into enrollee mode.
Here is a link to the code that I used to "fix" the issue: https://github.com/espressif/esp-idf/blob/master/examples/wifi/getting_started/station/main/station_example_main.c
I will mark this answer as correct and continue looking for the root problem. In the event that someone else know what actually could have caused this, feel free to post and I will update the correct answer. In the event that I find what the root problem is, I will update this answer as well.
EDIT: After continuing to dig, I believe that the problem was actually do to a multitude of errors in my code. Particularly, I was calling esp_netif_create_default_wifi_sta() and then not setting the WI-FI mode. I needed to add esp_wifi_set_mode(WIFI_MODE_STA), which was absent in my program. I believe setting the network stack to sta without changing the wifi mode was what caused my issue.

Can someone clarify IOS Safari Service Worker Support

Looking at the MDN documentation IOS/Safari fully supports ServiceWorkerGlobalScope.onfetch but when you look at the FetchEvent specification it says it is not supported at all by Safari.
In particular, I would like to store some state for each client and was hoping to use the fetchEvent.clientId property of the event to index it. Of course I presume I also have access to the fetchEvent.request object otherwise I can't see how a service worker can do anything useful and I could simulate clientID from a passed in parameter in the url. But the docs don't really tell me what IOS/Safari supports and doesn't so I don't know which way to go.
Can someone please tell me precisely what does IOS/Safari pass when it calls the defined onfetch function.
I found the answer to my question by using https://jakearchibald.github.io/isserviceworkerready/demos/fetchevent/
connecting my iPad to my Macbook and debugging my iPad. I was eventually able to open the web inspector for the Service worker for that page, and the console.log showed the event passed in.
FetchEvent.clientID is present but a zero length string. As it happens I did the same thing on my (linux) Desktop using Chrome and its also a zero length string, BUT it has another parameter resultingClientId with what looks like a UUID in it. That parameter is not there in Safari.
The FetchEvent.request is there, and in particular the URL. So I can generate my own client id in the client (I am using Date.now().toString() as that is good enough for my purposes) for use in the service worker. In fact my site without a service worker was using the in the URLs I need to intercept already, so I am happy that I have a solution.

How do you get IBM MobileFirst Platform ChallengeHandler to handle very large responses correctly?

When working with a large-sized data response from an HTTP Adapter, the size of the response appears to cause our challenge handler to fire a handleChallenge() method.
My question is, why would the size of the response cause the mobilefirst security challenge handler to fire, when the session is still valid?
More Details:
Our application uses an ISAM security appliance with Header based authentication. When an HTTP adapter call we make comes back with a content-length greater than 20,377, the adapter call triggers the handleChallenge() method of our challenge handler. When inspecting the response, we have seen that the responseJSON is actually populated with our required data, so really the handleChallenge should never have fired.
When we ping the adapter directly through the browser with the same parameters, it works fine. We've been able to isolate that this problem is occurring in the worklight.js / mobilefirst realm.
Does anyone have any idea if, or why, the Challenge Handler in worklight.js would not function as expected with a very large response size?
The bottom line is that it should. There is no reason for it not to.
If you have not been able to resolve this otherwise, my suggestion is to open an IBM PMR (support ticket) to have the development team investigate the issue.
We ended up ( sort of ) diagnosing it. At a certain payload size, the "/*secure {" fell off the response ( of which we're still not certain why. Our loginChallengeHandler function was based off of some example we found in some IBM documentation, and would improperly mark the response as a login form if the /*secure wasn't present. Once we tightened up the challenge handler, it worked.

Flash player API for browser extension

let's say we have a P2P multi-player Flash based game hosted on a website. Would it be possible to create a browser extension that would listen to what is going on within the Flash application? For example, I would like to know when a player connects to a room, gets kicked or banned, or simply leaves by himself. I'm sorry this is not really a specific question but I need a direction to start. Thanks in advance!
I can see a few ways to communicate between Flash and a browser plugin.
One is to open a socket to a server running on the local machine. Because of the security sandbox, this may not be the easiest approach, but if feasible, it is of course probably the one to go for because you've already got your socket-handling code written, and listening/writing to a additional socket isn't terribly complicated. For this approach, you just need your plugin to start listening on a socket, and get the flash applet to connect to it.
Another way might be to try something with passing messages in cookies. Pretty sure this would just cause much grief, though.
Another way, and I suspect this may turn out to be the easier path, is to communicate between Flash and JavaScript using the ExternalInterface class, then from JavaScript to the plugin. Adobe's IntrovertIM example should get you started if you can find a copy on the web.
In Flash, create two functions, a jsToSwf(command:String, args:Array<String>):Dynamic function, to handle incoming messages from JS that are sent to that callback, and a swfToJs(command:String, args:Array<String> = null):Dynamic function, which calls flash.external.ExternalInterface.call("swfToJs", command, args);.
To set it up, you need to do something like:
if (flash.external.ExternalInterface.available) {
flash.external.ExternalInterface.addCallback("jsToSwf", jsToSwf);
swfToJs("IS JS READY?");
}
(The two parameters to addCallback are what the function is called in JS, and what it's called in Flash. They don't have to be the same thing, but it sort of makes sense that they do)
In JS, you need the same functions: function swfToJs(command, params) accepts commands and parameter lists from Flash; and jsToSwf(command, params) calls getSwf("Furcadia").jsToSwf(command, params);.
getSwf("name") should probably be something like:
/** Get ref to specified SWF file.
// Unfortunately, document.getElementById() doesn't
// work well with Flash Player/ExternalInterface. */
function getSwf(movieName) {
result = '';
if (navigator.appName.indexOf("Microsoft") != -1) {
result = window[movieName];
} else {
result = document[movieName];
}
return result;
}
The only fiddly bit there is that you need to do a little handshake to make sure everyone's listening. So when you have Flash ready, it calls swfToJs("IS JS READY?"); then the JS side, on getting that command, replies with jsToSwf("JS IS READY!"); then on getting that, Flash confirms receipt with swfToJs("FLASH IS READY!"); and both sides set a flag saying they're now clear to send any commands they like.
So, you've now got Flash talking with JS. But how does JS talk with a browser extension? And, do you mean extension, or add-on, since there's a difference! Well, that becomes a whole 'nother can of worms, since you didn't specify which browser.
Every browser handles things differently. For example, Mozilla has port.emit()/port.on() and the older postMessage() as APIs for JS to communicate with add-ons.
Still, I think ExternalInterface lets us reduce a hard question (Flash-to-external-code comms) to a much simpler question (Js-to-external-code comms).

data channel using libjingle C/C++

I am looking for a very basic example of establishing a data channel using WebRTC. The peer_connection examples given are for audio/video and I am not able to run them to understand the code flow and write code for data channel on my own. I have done this using JavaScript for browser, now want to do the same for native application.
Have you check the peerconnection.cc for data channel creation API?
I saw this:
talk_base::scoped_refptr<DataChannelInterface>
PeerConnection::CreateDataChannel(
const std::string& label,
const DataChannelInit* config) {
talk_base::scoped_refptr<DataChannelInterface> channel(
session_->CreateDataChannel(label, config));
if (!channel.get())
return NULL;
observer_->OnRenegotiationNeeded();
return DataChannelProxy::Create(signaling_thread(), channel.get());
}
So in the peerconnection_client example, I think you can try create the data channel using peerconnection in the conductor.cc using peer_connection_ inside AddStreams and keep the data channel instance, then try send data using it after the answer is received.
Unfortunately I don't have the compilation env now to I can not try this myself.
Hope you can do it.
I was using an old revision of webrtc. There is an example called PCP_MAIN. This example demonstrates the basic file transfer between two peers. However this uses pseudo TCP. This is little hard to getting it work as data channels. Probably you might want to look something around RTP data channels.
I'm curious to know about some examples using SCTP.