智能家居机顶盒音量特征显示错误

问题描述 投票:0回答:1

我已经实现了

Smart Home Actions
Set-top Box
文档

这里我尝试添加

action.devices.traits.Volume
但出现以下错误

这是我的云函数代码

'use strict';

const functions = require('firebase-functions');
const {smarthome} = require('actions-on-google');
const {google} = require('googleapis');
const util = require('util');
const admin = require('firebase-admin');
// Initialize Firebase
admin.initializeApp();
const firebaseRef = admin.database().ref('/');
// Initialize Homegraph
const auth = new google.auth.GoogleAuth({
  scopes: ['https://www.googleapis.com/auth/homegraph'],
});
const homegraph = google.homegraph({
  version: 'v1',
  auth: auth,
});
// Hardcoded user ID
const USER_ID = '123';

exports.login = functions.https.onRequest((request, response) => {
  if (request.method === 'GET') {
    functions.logger.log('Requesting login page');
    response.send(`
    <!DOCTYPE html>
      <html>
        <head>
          <title>Page Title</title>
        </head>
        <body>

          <h1>Account Linking</h1>
          <form action="/login" method="post">
                <input type="hidden"
                  name="responseurl" value="${request.query.responseurl}" />
                <button type="submit" style="background-color: #4CAF50; /* Green */ border: none; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px;">
                  Clik to link your device
                </button>
              </form>

        </body>
      </html>
  `);
  } else if (request.method === 'POST') {
    // Here, you should validate the user account.
    // In this sample, we do not do that.
    const responseurl = decodeURIComponent(request.body.responseurl);
    functions.logger.log(`Redirect to ${responseurl}`);
    return response.redirect(responseurl);
  } else {
    // Unsupported method
    response.send(405, 'Method Not Allowed');
  }
});

exports.fakeauth = functions.https.onRequest((request, response) => {
  const responseurl = util.format('%s?code=%s&state=%s',
      decodeURIComponent(request.query.redirect_uri), 'xxxxxx',
      request.query.state);
  functions.logger.log(`Set redirect as ${responseurl}`);
  return response.redirect(
      `/login?responseurl=${encodeURIComponent(responseurl)}`);
});

exports.faketoken = functions.https.onRequest((request, response) => {
  const grantType = request.query.grant_type ?
    request.query.grant_type : request.body.grant_type;
  const secondsInDay = 86400; // 60 * 60 * 24
  const HTTP_STATUS_OK = 200;
  functions.logger.log(`Grant type ${grantType}`);

  let obj;
  if (grantType === 'authorization_code') {
    obj = {
      token_type: 'bearer',
      access_token: '123access',
      refresh_token: '123refresh',
      expires_in: secondsInDay,
    };
  } else if (grantType === 'refresh_token') {
    obj = {
      token_type: 'bearer',
      access_token: '123access',
      expires_in: secondsInDay,
    };
  }
  response.status(HTTP_STATUS_OK)
      .json(obj);
});

const app = smarthome();



const boxDetails = [{
  id: 'washer',
  type: 'action.devices.types.SETTOP',
  traits: [
    'action.devices.traits.OnOff',
    'action.devices.traits.Volume',
  ],
  name: {
    defaultNames: ['Test TV'],
    name: 'Test TV',
    nicknames: ['Test TV'],
  },
  deviceInfo: {
    manufacturer: 'Test',
    model: 'Test',
    hwVersion: '1.0',
    swVersion: '1.0.1',
  },
  willReportState: true,
  attributes: {
    pausable: true,
  },
}]

app.onSync((body) => {
  return {
    requestId: body.requestId,
    payload: {
      agentUserId: USER_ID,
      devices: boxDetails,
    },
  };
});

const queryFirebase = async (deviceId) => {
  const snapshot = await firebaseRef.child(deviceId).once('value');
  const snapshotVal = snapshot.val();
  return {
    on: snapshotVal.OnOff.on,
    volumeLevel: 20
  };
};

const queryDevice = async (deviceId) => {
  const data = await queryFirebase(deviceId);
  return {
    on: data.on,
    currentVolume : 20,
  };
};

app.onQuery(async (body) => {
  const {requestId} = body;
  const payload = {
    devices: {},
  };
  const queryPromises = [];
  const intent = body.inputs[0];
  for (const device of intent.payload.devices) {
    const deviceId = device.id;
    queryPromises.push(queryDevice(deviceId)
        .then((data) => {
          payload.devices[deviceId] = data;
        },
        ));
  }
  await Promise.all(queryPromises);
  return {
    requestId: requestId,
    payload: payload,
  };
});

const updateDevice = async (execution, deviceId) => {
  functions.logger.info(`deviceId ${deviceId}`);
  const {params, command} = execution;
  let state; let ref;
  switch (command) {
    case 'action.devices.commands.OnOff':
      state = {on: params.on};
      ref = firebaseRef.child(deviceId).child('OnOff');
      break;
    case 'action.devices.commands.setVolume':
      state = {currentVolume: params.volumeLevel};
      ref = firebaseRef.child(deviceId).child('Volume');
      break;
  }

  return ref.update(state)
      .then(() => state);
};

app.onExecute(async (body) => {
  const {requestId} = body;
  const result = {
    ids: [],
    status: 'SUCCESS',
    states: {
      online: true,
    },
  };

  const executePromises = [];
  const intent = body.inputs[0];
  
  for (const command of intent.payload.commands) {
    for (const device of command.devices) {
      for (const execution of command.execution) {
        executePromises.push(
            updateDevice(execution, device.id)
                .then((data) => {
                  result.ids.push(device.id);
                  Object.assign(result.states, data);
                })
                .catch(() => functions.logger.error('EXECUTE', device.id)),
        );
      }
    }
  }

  await Promise.all(executePromises);
  return {
    requestId: requestId,
    payload: {
      commands: [result],
    },
  };
});

app.onDisconnect((body, headers) => {
  functions.logger.log('User account unlinked from Google Assistant');
  return {};
});

exports.smarthome = functions.https.onRequest(app);

exports.requestsync = functions.https.onRequest(async (request, response) => {
  response.set('Access-Control-Allow-Origin', '*');
  functions.logger.info(`Request SYNC for user ${USER_ID}`);
  try {
    const res = await homegraph.devices.requestSync({
      requestBody: {
        agentUserId: USER_ID,
      },
    });
    functions.logger.info('Request sync response:', res.status, res.data);
    response.json(res.data);
  } catch (err) {
    functions.logger.error(err);
    response.status(500).send(`Error requesting sync: ${err}`);
  }
});

exports.reportstate = functions.database.ref('{deviceId}').onWrite(
    async (change, context) => {
      functions.logger.info('Firebase write event triggered Report State');
      const snapshot = change.after.val();

      const requestBody = {
        requestId: 'ff36a3cc', 
        agentUserId: USER_ID,
        payload: {
          devices: {
            states: {
              [context.params.deviceId]: {
                on: snapshot.OnOff.on,
                volumeLevel : 40,
              },
            },
          },
        },
      };

      const res = await homegraph.devices.reportStateAndNotification({
        requestBody,
      });
      functions.logger.info('Report state response:', res.status, res.data);
    });


exports.updatestate = functions.https.onRequest((request, response) => {
  firebaseRef.child('set-to-box').update({
    OnOff: {
      on: request.body.on,
    },

    Volume:{
      volumeLevel :40,
    }
  });

  return response.status(200).end();
});

您能给我推荐一些示例代码吗

action.devices.types.SETTOP

我检查了很多块,但我得到了同样的错误

google-cloud-platform google-cloud-functions actions-on-google google-smart-home
1个回答
0
投票

查看您的云函数代码后,我发现该问题可能与您如何处理action.devices.traits.Volume的updateDevice函数有关。在 updateDevice 函数中,您正确处理了 action.devices.commands.OnOff 命令,但处理 action.devices.commands.setVolume 命令的方式似乎存在潜在问题。

在此代码块中,您正在更新“Volume”特征的状态,但它在 JSON 响应中的结构可能不正确,从而导致错误。

case 'action.devices.commands.setVolume':
  state = {currentVolume: params.volumeLevel};
  ref = firebaseRef.child(deviceId).child('Volume');
  break;

以下是修改 updateDevice 函数的方法:

const updateDevice = async (execution, deviceId) => {
  functions.logger.info(`deviceId ${deviceId}`);
  const { params, command } = execution;
  let state;
  let ref;

  switch (command) {
    case 'action.devices.commands.OnOff':
      state = { on: params.on };
      ref = firebaseRef.child(deviceId).child('OnOff');
      break;
    case 'action.devices.commands.setVolume':
      state = { currentVolume: params.volumeLevel };
      ref = firebaseRef.child(deviceId).child('Volume');
      break;
  }

  // Include the device in the response
  const device = {
    id: deviceId,
    states: state,
  };

  return ref
    .update(state)
    .then(() => device);
};
© www.soinside.com 2019 - 2024. All rights reserved.