Google Cloud IoT Core Node.js Client: How to get lastHeartbeatTime of a device in a google cloud function? - google-cloud-iot

I use the DeviceManagerClient.listDevices function of the 2.1.1 API in cloud functions
and it works right, apart from the fact that most of the properties of the got IDevices are null.
The id, numId, and metadata properties are not null but everything else inclusive lastHeartbeatTime.
How can I get lastHeartbeatTime of a device from a cloud function using the Node.js API?
Best regards,
Árpád

Thank you Kolban for your answer!
This is a usage example:
const listDevicesResponse = await iotClient.listDevices({
parent: iotClient.registryPath(process.env.GCLOUD_PROJECT!, CLOUD_REGION, REGISTRY_ID),
fieldMask: {paths: ['last_heartbeat_time']}
// For a full list of fieldMask paths see https://github.com/googleapis/nodejs-iot/issues/178#issuecomment-580999577
});
const devices = listDevicesResponse[0];
for(const device of devices) {
if (devices === null) continue;
functions.logger.info(`device.id:${device.id}, device.lastHeartbeatTime?.seconds:${device.lastHeartbeatTime?.seconds}`);
}

Related

ReferenceError: localStorage is not defined on Deno Deploy

I'm using localStorage on the server and it works fine locally. But when I deployed my code to Deno deploy is not defined
Do I need to import the localStorage? I Deno.com I couldn't find any docs talking about localStorage so maybe that feature is not supported yet. In that case, where can I deploy my code to use it? Thanks
import {Handlers, PageProps} from "$fresh/server.ts";
interface Data {
email: string[]
}
export const handler: Handlers<Data> = {
GET(_req, ctx) {
const emailsStorage = localStorage.getItem("email");
const email = emailsStorage ? JSON.parse(emailsStorage) : [];
console.log(email);
return ctx.render({ email });
},
};
export default function EmailPage({ data }: PageProps<Data>) {
const { email } = data;
return (
<main>
<h1>Emails</h1>
<ul>
{email.map((email) => (
<li>{email}</li>
))}
</ul>
</main>
);
}
The full list of available APIs is here (note that localStorage is not listed).
Deploy does not offer any persistent data storage mechanism. After your deployed code finishes executing in response to a request, all of the JS memory is destroyed, so if you want to work with mutable data that persists between requests, then you'll have to store that data yourself elsewhere — e.g. by sending the data in a network request to another server / hosted database / etc. and then requesting it when you need it.
The docs include several "persist data" tutorials that you can use as a guide/reference in order to learn.
You can persist data in local storage by creating a virtual local Storage by using this code.
import { installGlobals } from "https://deno.land/x/virtualstorage#0.1.0/mod.ts";
installGlobals();
localStorage.getItem("email") will work on Deno Deploy also.

window.ethereum.providers undefined - allow user to select MetaMask OR Coinbase Wallet as web3 provider

How do we allow users to choose which browser wallet / provider they use when interacting with web3 websites? This is for basic HTML / WordPress websites not using TypeScript / React, etc.
According to Coinbase Docs, the Coinbase Wallet SDK is not needed: "You can use this provider in your dapp to request users' Ethereum accounts, read on-chain data, and have the user sign messages and transactions, without using the Coinbase Wallet SDK."
https://docs.cloud.coinbase.com/wallet-sdk/docs/injected-provider
Currently, my integration works with MetaMask without issue. However, when trying to choose the Coinbase Wallet (browser extension) as my provider, there doesn't seem to be a way to do so.
If window.ethereum gets set by the Coinbase Wallet extension, there is suppose to be a window.ethereum.providers object. You can then go through each one, find MetaMask or Coinbase, and set the preferred one as the provider:
MetaMask conflicting with Coinbase wallet
However, it seems that MetaMask is has priority over this, and sets window.ethereum WITHOUT the .providers object.
I've attempted to load / find the Coinbase Wallet provider during and after Page Load, but it doesn't seem to exist. Again, I'm assuming MetaMask gets set as the provider before Coinbase injection even exists.
Is there a way to let the user set the provider / wallet that is being used using basic web3 JS?
Have had some testing with this function with coinbase and metamask extensions both installed on chrome. It will open a window for you to choose which wallet you want to connect and then use the first address in that wallet to set the account.
async function getWallet() {
try{
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
let account = accounts[0];
return account
} catch (error) {
console.log(error);
}
}
https://docs.cloud.coinbase.com/wallet-sdk/docs/injected-provider-guidance
const connectWallet = async () => {
if (typeof window.ethereum !== "undefined") {
let provider = window.ethereum;
// edge case if MM and CBW are both installed
if (window.ethereum.providers?.length) {
window.ethereum.providers.forEach(async (p) => {
if (p.isMetaMask) provider = p;
});
}
await provider.request({
method: "eth_requestAccounts",
params: [],
});
}
};
I think the way how implemented your code has some bugs. this code above is clear

How to get the current https functions endpoint for firebase when using/not using emulator

I have a graphql api running on a firebase function and I develop locally for the most part.
Before when I called the firebase functions directly I would use the connectFunctionsEmulator function to conditionally connect to my local emulator and when I called the functions using getFunctions it would know to call my localhost endpoint.
However I'm trying to use Apollo client and I'm not sure how to determine when the local emulators have been connected and when they have not as well as how to determine the absolute url when calling the function like the way firebase does when I call it using the firebase functions helpers.
I went snooping through the code and when I call the connectFunctionsEmulator function it updates a variable called functionsInstance.emulatorOrigin.
This is not present in the functions typing but I'm still able to access the value by doing getFunctions().emulatorOrigin.
If the value is not set to null that means firebase will be talking to my emulators and not to the live endpoint.
function getGraphQLUri(): string {
const functions = getFunctions();
const app = getApp();
const { projectId } = app.options;
const { region } = functions;
// emulatorOrigin is not defined in the typings but it exists
// #ts-ignore
const emulator = functions.emulatorOrigin;
let url: string = "";
if (emulator) {
url = `${emulator}/${projectId}/${region}/graphql`;
} else {
url = `https://${region}-${projectId}.cloudfunctions.net/graphql`;
}
return url;
}
I would appreciate if someone at Google can confirm whether this approach might continue to be supported in the future.

Firebase Function - Client IP always Internal to Google

I am writing a Firebase Function, specifically for Dialogflow chatbot fulfillment. I am having trouble getting an accurate client IP address regardless of how I am testing it.
I've seen on various posts the various ways to read client IP, but they are either undefined or an internal Google IP from one of their data centers.
I've tried reading:
"x-forwarded-for" header
req.connection.remoteAddress
req.ip
req.ips (collection of all of them, there is only ever 1 in the collection)
Any help would be much appreciated. I am trying to log analaytics around user interactions, and right now the IPs are all incorrect.
I've tried the following code which is provided here:
const functions = require('firebase-functions');
const util = require('util');
exports.helloWorld = functions.https.onRequest((req, res) => {
// For Firebase Hosting URIs, use req.headers['fastly-client-ip']
// For callable functions, use rawRequest
// Some users have better success with req.headers['x-appengine-user-ip']
const ipAddress = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
const headers = JSON.stringify(req.headers, null, 2);
const message = util.format("<pre>Hello world!\n\nYour IP address: %s\n\nRequest headers: %s</pre>", ipAddress, headers);
res.send(message);
});
When tested (even with mobile data), it returned the public IP of the caller and not a Google Internal IP.
If try this, do you continue getting internal IPs?

Firebase Auth successful, but Database Ref set and update does not happen in electron app version 1.4.2

I'm able to authorize the Firebase app from my existing Electron app using firebase.auth().signInWithCustomToken. The promise for this method resolves and I'm able to obtain the current authorized user with firebase.auth().currentUser.uid.
At this point I must technically be able to write to /users/<currentUser>. However calling the userRef.set() and userRef.update() methods does not update the database reference and fails silently (both the callback and the promise from these methods do not resolve and there is no error thrown).
What is strange is that the exact same code works in a different, newly created Electron app. My code looks like below:
const writeToFirebase = (customToken) => {
syncApp.auth().signInWithCustomToken(customToken).then(user => {
const userId = firebase.auth().currentUser.uid; // this is successfull
const userRef = firebase.database().ref("/users/" + userId);
userRef.set({data: data}, () => { //callback does not trigger });
userRef.update({data: data})
.then(() => {//promise does not resolve})
.catch(err) => {// promise is not rejected either! }
});
}
Any pointers on how to go about debugging this would be helpful.
I discovered the problem. It's unlikely anybody else would have the same issue, but if you do, take a look at the userAgent value in your browserWindow.loadURL in Electron.
Mine was set to an Android mobile device & Firebase was not setting/updating due to this reason. I presume the Firebase server reacts differently when it sees a mobile userAgent and I was using the Firebase JS SDK and not the Android SDK which caused the issue.

Resources