Qingping Air monitor lite homeyscript

Hi all,

I made a quick integration to get data from Qingping+ for the Qingping Air Monitor Lite device. Be sure to use the Qingping+ app on your phone and use an account. The device must be set in qingping mode instead of homekit mode.
Be sure to adjust the Authorization token as described here: https://developer.qingping.co/main/oauthApi.

const params = new URLSearchParams();

params.append('grant_type', 'client_credentials');

params.append('scope', 'device_full_access');

var result = await fetch("https://oauth.cleargrass.com/oauth2/token", {

  method: 'post',

  headers: {

    'Authorization': 'Basic CHANGE_THIS_KEY',

  },

  body: params,

});

if (!result.ok)   throw new Error(result.statusText);

const body = await result.json();

console.log(body)

var access_token= body.access_token;

await tag("qingping_access_token", access_token);

// get device data

var result = await fetch("https://apis.cleargrass.com/v1/apis/devices?timestamp=" + Date.now().toString(), {

  method: 'get',

  headers: {

    'Authorization': 'Bearer ' + access_token,

  },

});

if (!result.ok)   throw new Error(result.statusText);

const body2 = await result.json();

var data = body2.devices[0].data

console.log(data)

var {timestamp,temperature,humidity,  co2,pm25} = data;

console.log(timestamp,temperature,humidity,  co2,pm25);

await tag("qingping_timestamp", timestamp.value);

await tag("qingping_temperature", temperature.value);

await tag("qingping_humidity", humidity.value);

await tag("qingping_co2", co2.value);

await tag("qingping_pm25", pm25.value);
3 Likes

Hello Thomas,

Thanks for the integration.
Could you help me how to get the Authorization token? I cant really figure it out.

And do i use this code with HomeyScript?

Yes! Do you have a app key and app secret from https://developer.qingping.co/personal/permissionApply?

I have a key and secret, do I need to do anything else?

And can you share some inspirational flows?

I retrieved this from developer page
Apkey:xxxxxxxxx
App secret: yyyyyyy

I edited the script accordingly:

'Authorization': 'xxxxxxxxxx', or
'Authorization': 'yyyyyyyyyy',

This is the output of the script

:x: Script Error
:warning: Error: Bad Request
at Qingping.js:21:25
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async HomeyScriptApp.runScript (/app.js:312:22)
at async Object.runScript (/api.js:24:18)

Hi @tjaadvd , thanks for your script. I used it for my Homey except I inserted my app key from Qingping, where you typed ‘change_this_key’. I get the same script error output as Wout in the last message. Not sure where my app secret key goes.

Can you help? I’m afraid I’m new to scripts so am quite confused by how they work! Appreciate your time.

Hi guys,

The trick to generate the Authorization key is to combine the client_id (App Key) and client_secret (App Secret) and ‘encode’ them with base64. Base64 is an encoding originally build for email attachments.

  • Go to https://www.base64encode.org/
  • paste the App Key, then the ‘:’ character, and then the App Secret. For example “_GoSI9xxx:c2ba57537b5311eb9e7fxxxxxxxxxxxx”.
  • Click on the convert button
  • Copy the resulting encoded string (for example “X0dvU0k5eU…”)
  • Then replace CHANGE_THIS_KEY with the string that you copied. The line now looks like this: ‘Authorization’: ‘Basic X0dvU0k5eU…’,

That should do the trick! This script uses the first qingping device in your account. If you have multiple you can create a new script and change devices[0] to devices[1].

If you’ve created the homeyscript (through https://my.homey.app) and it works, you can use it with a flow like this: Gedeelde Flow | Homey. That flow runs every 10 minutes, and uses the homeyscript in the ‘And’ (conditions) section. The first actions that set Logic aren’t important. I’ve created a virtual device in Homey of type ‘sensor’ and this script sets the values for that virtual device. In order to create a virtual device in Homey you have to go to Settings in the app → Experiments → Virtual devices.

Great! thank you, I can now pull air quality data via homeyscript. unfortunately it seems that the Homey app now no longer includes virtual sensors, only some other virtual types e.g. switch. the functionality might be suspended for now.

You can use the Virtual Devices app for sensors.

1 Like

That works. Thanks!

1 Like

@tjaadvd

Hi, great you have figured this out!
I could not use my Qingping on Homey 2023 any more.

I have one question, my script is running fine, i got the richt values.

{
timestamp: { value: 1679155200 },
temperature: { value: 21.49 },
humidity: { value: 52.39 },
co2: { value: 789 },
pm25: { value: 1 },
pm10: { value: 2 }
}
{ value: 1679155200 } { value: 21.49 } { value: 52.39 } { value: 789 } { value: 1 }

———————————————————
:white_check_mark: Script Success
:leftwards_arrow_with_hook: Returned: undefined

But when using it in a flow i got an error back, see screenshot.

Maybe you can help me with this?

THX!!!

I Have the same problem. Don’t know what the problem is

It looks like the script give an error. I can’t test a new script, but i asked ChatGPT to rewrite the old script. Maybe, just maybe it works;

const { OAuth2 } = Homeyapi('oauth2');
const { Http } = Homeyapi('http');

const oauth2 = new OAuth2({
  client_id: 'CHANGE_THIS_KEY',
  client_secret: '',
  scopes: ['device_full_access'],
  authorization_uri: 'https://oauth.cleargrass.com/oauth2/auth',
  token_uri: 'https://oauth.cleargrass.com/oauth2/token'
});

const http = new Http();

(async () => {
  try {
    const { access_token } = await oauth2.getToken();

    // Store the access token as a tag
    await Homey.flowToken.set('qingping_access_token', access_token);

    // Get device data
    const { devices } = await http.get('https://apis.cleargrass.com/v1/apis/devices', {
      headers: {
        'Authorization': `Bearer ${access_token}`
      }
    });

    // Extract the data from the first device
    const { data } = devices[0];

    // Store the data values as tags
    await tag('qingping_timestamp', data.timestamp.value);
    await tag('qingping_temperature', data.temperature.value);
    await tag('qingping_humidity', data.humidity.value);
    await tag('qingping_co2', data.co2.value);
    await tag('qingping_pm25', data.pm25.value);

    // Log the data values
    console.log(data.timestamp.value, data.temperature.value, data.humidity.value, data.co2.value, data.pm25.value);
  } catch (error) {
    console.error(error);
  }
})();

This is the result of the script:

:x: Script Error
:warning: ReferenceError: Homeyapi is not defined
at Qingping3.js:1:20
at processTicksAndRejections (node:internal/process/task_queues:96:5)

Ok, was worth a try😰

Okiedokie, I have this now completely up and running… I improved the script with the help and inspiration of this forum, ChatGPT and some apps…

const params = new URLSearchParams();

params.append('grant_type', 'client_credentials');
params.append('scope', 'device_full_access');

const client_id = 'FILL_IN_APPKEY';
const client_secret = 'FILL_IN_APPSECRET';
const credentials = Buffer.from(client_id + ':' + client_secret).toString('base64');

var result = await fetch("https://oauth.cleargrass.com/oauth2/token", {
  method: 'post',
  headers: {
    'Authorization': 'Basic ' + credentials,
  },
  body: params,
});

if (!result.ok)   throw new Error(result.statusText);

const body = await result.json();

console.log(body)

var access_token = body.access_token;

await tag("qingping_access_token", access_token);

// get device data

var result = await fetch("https://apis.cleargrass.com/v1/apis/devices?timestamp=" + Date.now().toString(), {
  method: 'get',
  headers: {
    'Authorization': 'Bearer ' + access_token,
  },
});

if (!result.ok)   throw new Error(result.statusText);

const body2 = await result.json();

var data = body2.devices[0].data

console.log(data)

var {timestamp,temperature,humidity,  co2,pm25, pm10} = data;

console.log(timestamp,temperature,humidity,  co2,pm25, pm10);

await tag("qingping_timestamp", timestamp.value);
await tag("qingping_temperature", temperature.value);
await tag("qingping_humidity", humidity.value);
await tag("qingping_co2", co2.value);
await tag("qingping_pm25", pm25.value);
await tag("qingping_pm10", pm10.value);

Used apps:

  • HomeyScript (see above)
  • Qingping installed NOT via Homekit (topic start)
  • Portal Qingping (mentioned in topic start)
  • Created virtual Device with this Device Capabilities
  • Created this flow

Note in the script, change this:
const client_id = ‘FILL_IN_APPKEY’;
const client_secret = ‘FILL_IN_APPSECRET’;

To import the app into Device Capabilities app, use this TEF:

[tef:AVD:"H4sIAAAAAAACA42Wa4+iSBSG/4tfnQ53hU72g6AoCKiIF3qzmRRQQMmlEAoUJvPfl97uaWe7e0yTkErOqfOe5wVOhR+DADbIh5qP88HjYMFX2uTlUiYMs2tZ3jM3nage1LGK2KG+PGuT8UaSLkGrCC2twImYLO3ruqSmRztQFQ4JRy1LVubKNphxGAoeN5QahxnBNRXoy+XV4w14PPHhia9TquZInxhKbCGtdCcp1kYncXRaetqhFpoFGoZlVVpUk9ZXdE1zEPGutnWsc0EYFHSesz3v6Nou19YluXb2JEVXw3KmJr3APt1it5k6SFLW06YyZS3L4NYCvmLFiYNMV0zoJLdKJgEnz3iSTe0Jqyg2IZBbAFDSgCqm8GomVJ5grYYHd93IgLILEG9nNM9auXyhlwgXdkDhs4ZhnC32xT55mpPD6pIvCUqY1ihP9jLhtcXcOrhz1ZckUTv7XX2s1AZtjCvjV1ezExf4xIw1ZyZn+mlYnV3mks78EDgNFMKNoXssvMypU+uc+eAg16dzPD5fnzIHMSArMHbMYxQcrHmorPeVXrCZOVrsdpcRlxELQGtbZJvR7MSwemQc28gR9/YWF+hsakJjTOkrd45inZIm+yuskKnOkwi5wsGkxnOhvSTKccQdG3bBs4oGuugyLwXaQZRsBhOMPRUx60J3HFs+Wy7016Sc7vUKLoViNtfMnZ+MN7k2VfcN7jDgKmEc0U641d0xvmRxmi3ZneZEe7gOTsvcvmqTLjmoy3qz43I/oVeeLtMoPvCBvZ9pphuXC8jMdguY1gG/y7aEy10piU8kCbEsC8NanRnqvoNZbZG2UTY7RM6znMv3orLpQNk61o7T7enRWG19biXq6rDbucGlQ5RZDuWOBd48OrT8eC3tmEoE7lOmdduwkrRNkuPNPJSIN2/cZl8uT1Rz8j1JjFLZfQrryhgPV6T/RqWGY0WYZ08kDY61Q7X1vqmS8rgtzFk/T38Nvg38uiI4e561avD44+e3AS5RhHKQakE/fKORJHFQGD34NMM88P2Lf5BGUHzwRBHQYjgCI5/vRSpICMqjZ4UBzGEZtd8bkNbw+7MsATkZPOZ1mn4b5HXmwXIVOvBKVATToC+hb2Hrv/VXQrglZIxTCPJPSuSaEPxZQgEZLMEnCQNVv/f2037tHeQVLge/djFWX92HHZgVvQqp699yW1iAPgYVUAAPpYgg2EuEIK3gbU+ML5Nn4QyCqi7hd/JLqYQ3JaWEvY6a4osCymceUtY3DRuGKfT7Zze4VUyhjzLwjMy8U3FA9K7+Ja7lFYpi8k6cfTW4qDMUINK+dWC/4I794C7+IHPXGvuJDfYPNth7NrhXG8qKfWvNfcEB98GBj39TuAvP3eDpdxUf4Ll78PwrfJGxwltv/gv0/Af6/0vcxef/gMrfQxXeUBn6rY/wBVThPqpwF1X4A6rwGWp/dL38N7yibvoDqejvvhcYPP79z89/AXaXpZlYCAAA":/tef]

I can confirm that is works for me,
Thanks

1 Like