How to solve the error "socket.on is not a function"

I want to add a device based on the 433MHz protocol to Homey, and I have already created an app and a driver. However, when I try to pair the device, I get an error message when I click on the driver that says “socket.on is not a function.” This means that the front-end and back-end cannot connect through this socket when there is no device sending the pairing protocol?

This is a bug in your driver.

Is there a solution? Is it because there’s something wrong with my code? Or is it something else…

There’s something wrong with your code. But without sharing it nobody will be able to point out the problem.

1 Like

device.js

'use strict';

const Homey = require('homey');

module.exports = class MyDevice extends Homey.Device {

  /**
   * onInit is called when the device is initialized.
   */
  async onInit() {
    this.log('Dimmer Device initialized:', this.getName());

    this.registerCapabilityListener('onoff', this.onCapabilityOnoff.bind(this));
    this.registerCapabilityListener('dim', this.onCapabilityDim.bind(this));
    this.log('Capability listeners registered for onoff and dim');
  }

  async onCapabilityOnoff(value) {
    this.log('Received onoff command:', value ? 'Turn on' : 'Turn off');
    const command = value ? '00000001' : '00000000';
    this.sendSignal(command);
  }

  async onCapabilityDim(value) {
    const dimLevel = Math.round(value * 15).toString(2).padStart(8, '0');
    this.log('Received dim command:', value, 'Calculated dim level:', dimLevel);
    this.sendSignal(dimLevel);
  }

  sendSignal(command) {
    const payload = `00000001${this.getData().id.toString(2).padStart(8, '0')}${command}`;
    const binaryPayload = payload.split('').map(bit => parseInt(bit, 10));

    this.log('Sending signal with payload:', binaryPayload);

    this.getSignal().tx(binaryPayload, (err) => {
      if (err) {
        this.error('Error sending signal:', err);
      } else {
        this.log('Signal sent successfully:', binaryPayload);
      }
    });
  }

  getSignal() {
    return Homey.Signal433.getSignal('dimmer_signal');
  }

  /**
   * onAdded is called when the user adds the device, called just after pairing.
   */
  async onAdded() {
    this.log('MyDevice has been added');
  }

  /**
   * onSettings is called when the user updates the device's settings.
   * @param {object} event the onSettings event data
   * @param {object} event.oldSettings The old settings object
   * @param {object} event.newSettings The new settings object
   * @param {string[]} event.changedKeys An array of keys changed since the previous version
   * @returns {Promise<string|void>} return a custom message that will be displayed
   */
  async onSettings({ oldSettings, newSettings, changedKeys }) {
    this.log('MyDevice settings were changed');
  }

  /**
   * onRenamed is called when the user updates the device's name.
   * This method can be used this to synchronise the name to the device.
   * @param {string} name The new name
   */
  async onRenamed(name) { 
    this.log('MyDevice was renamed');
  }

  /**
   * onDeleted is called when the user deleted the device.
   */
  async onDeleted() {
    this.log('MyDevice has been deleted');
  }

};

driver.compose.json

{
  "name": {
    "en": "Light bulb"
  },
  "class": "light",
  "capabilities": [
    "dim",
    "onoff"
  ],
  "platforms": [
    "local"
  ],
  "connectivity": [
    "rf433"
  ],
  "images": {
    "small": "{{driverAssetsPath}}/images/small.png",
    "large": "{{driverAssetsPath}}/images/large.png",
    "xlarge": "{{driverAssetsPath}}/images/xlarge.png"
  },
  "pair": [
  {
    "id": "list_devices",
    "template": "list_devices",
    "navigation": {
      "next": "add_devices"
    }
  },
  {
    "id": "add_devices",
    "template": "add_devices"
  }
  ]
}

driver.js

'use strict';

const Homey = require('homey');

module.exports = class MyDriver extends Homey.Driver {
  async onInit() {
    this.log('433 MHz Dimmer Driver initialized');
  }

  onPair(socket) {
    if (!socket || typeof socket.on !== 'function') {
      this.error('Socket initialization failed: socket.on is not a function.');
      return;
    }
  
    this.log('Socket initialized successfully for pairing.');
  
    let devices = []; 
  
    socket.on('list_devices', async (data, callback) => {
      this.log('Listening for devices during pairing...');
      devices = [];
  
      try {
        const signal = this.homey.rf.getSignal433('dimmer_signal');
  
        const handlePayload = (payload) => {
          const decodedSignal = this.decodeSignal(payload);
          this.log('Decoded signal:', decodedSignal);
  
          if (this.isValidDevice(decodedSignal)) {
            const newDevice = { 
              name: `Dimmer ${decodedSignal.id}`, 
              data: { id: decodedSignal.id } 
            };
            if (!devices.find((device) => device.data.id === decodedSignal.id)) {
              devices.push(newDevice);
              this.log('Device added:', newDevice);
            }
          }
        };
  
        signal.on('payload', handlePayload);
  
        setTimeout(() => {
          signal.removeListener('payload', handlePayload); 
          this.log('Devices found:', devices);
          callback(null, devices.length > 0 ? devices : []); 
        }, 10000);
      } catch (err) {
        this.error('Error during pairing process:', err);
        callback(null, []); 
      }
    });
  
    socket.on('add_device', (device, callback) => {
      this.log('Device added successfully:', device);
      callback(null, device);
    });
  }
  

  decodeSignal(payload) {
    const binaryString = payload.join('');
    const type = binaryString.substring(0, 8); 
    const id = binaryString.substring(8, 16); 
    const command = binaryString.substring(16, 24); 

    this.log(`Decoded Signal - Type: ${type}, ID: ${id}, Command: ${command}`);

    return {
      type: parseInt(type, 2),
      id: parseInt(id, 2),
      command,
    };
  }

  isValidDevice(decodedSignal) {
    const isValid = decodedSignal.type === 1; 
    this.log(`Device validation result: ${isValid}`);
    return isValid;
  }
};

Please help me with it, because I’ve been stuck here for too long :frowning:
It is worth mentioning that the template folder under drivers in the.homeycompose directory of my app project is empty, do I need to add list_devices.html and add_devices.html files myself?
I add list_devices.html and add_devices.html file to .homeycompose/drivers/template such as below
list_devices.html

<div class="step">
    <h1>Discovering Devices</h1>
    <p>Searching for 433MHz devices...</p>
    <style>
      .spinner {
        margin: 20px auto;
        border: 8px solid #f3f3f3;
        border-top: 8px solid #3498db;
        border-radius: 50%;
        width: 40px;
        height: 40px;
        animation: spin 1s linear infinite;
      }
  
      @keyframes spin {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
      .message {
        text-align: center;
        font-size: 16px;
        color: #666;
        margin-top: 20px;
      }
    </style>
    <div class="spinner"></div>
    <div class="message">
      {{#if devices.length}}
        <p>New devices found. Select a device to continue.</p>
      {{else}}
        <p>No devices found. Please try again or ensure your device is in pairing mode.</p>
      {{/if}}
    </div>
  </div>
  

add_devices.html

<div class="step">
    <h1>Adding Device</h1>
    <p>Connecting your 433MHz device to Homey...</p>
    <style>
      .spinner {
        margin: 20px auto;
        border: 8px solid #f3f3f3;
        border-top: 8px solid #3498db;
        border-radius: 50%;
        width: 40px;
        height: 40px;
        animation: spin 1s linear infinite;
      }
  
      @keyframes spin {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
      .message {
        text-align: center;
        font-size: 16px;
        color: #666;
        margin-top: 20px;
      }
    </style>
    <div class="spinner"></div>
    <div class="message">
      <p>Please wait while the device is being added...</p>
    </div>
  </div>
  

And then i clicked the driver in homey app it will show below error

This is SDKv2 code, and SDKv2 has been deprecated for a while now. The SDKv3 equivalent can be found here.

1 Like

Thank you~i will have a look.

It’s worked out. Thank you very much

1 Like