Skip to content

Instantly share code, notes, and snippets.

@josiahbryan
Last active July 17, 2022 01:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josiahbryan/961dcf86147527ed23fa4ed976304970 to your computer and use it in GitHub Desktop.
Save josiahbryan/961dcf86147527ed23fa4ed976304970 to your computer and use it in GitHub Desktop.
Simple controller for use with the Wangdd22 Ethernet Relay
//
// Simple controller for use with the Wangdd22 Ethernet Relay, available on Amazon for ~$35
//
// See https://www.amazon.com/dp/B01MRQTFMJ?psc=1&ref=ppx_yo2ov_dt_b_product_details
//
// Special thanks to commentors on the product listing:
// Python Client: https://www.amazon.com/gp/customer-reviews/RAEHN60VSX3LV/ref=cm_cr_dp_d_rvw_ttl?ie=UTF8&ASIN=B01MRQTFMJ
// Config format: https://www.amazon.com/gp/customer-reviews/R19ZMADG7S2GX2/ref=cm_cr_dp_d_rvw_ttl?ie=UTF8&ASIN=B01MRQTFMJ
//
// This client just turns on/off the relays, doesn't handle config, but could easily be added thanks to the info
// in the linked comments above.
//
// Author: Josiah Bryan <josiahbryan@gmail.com>
//
import EventEmitter from 'events';
import net from 'net';
const PatchedLogger = global.console;
PatchedLogger.debug = global.console.log;
const NUM_RELAYS = 2;
const RELAY_ON = '1';
const RELAY_OFF = '2';
export class Wangdd22RelayClient extends EventEmitter {
/**
* Create an instance of the client and immediately connect. Will automatically reconnect
* if disconnected.
*
* @param {string} opts.host [default: 192.168.1.100] IP of the relay, defaults to factory-default setting
* @param {number} opts.port [default: 6722] Control port of the relay, probably won't need to change
* @param {bool} opts.reconnect [default: true] If true, will reconnect after `reconnectTimeout` ms when socket disconnects (unless you call '.end' on the client, which will disable reconnection)
* @param {number} opts.reconnectTimeout [default: 1000] Reconnection delay
* @param {string} opts.logger [default: console] Logger to use for debugging info (expects .debug and .info methods)
* @param {string} opts.name [default: 'Wangdd22RelayClient'] Name to print when logging for this client
*/
constructor({
host = '192.168.1.100',
port = 6722,
reconnect = true,
reconnectTimeout = 1000,
logger = PatchedLogger,
name = Wangdd22RelayClient.name,
} = {}) {
super();
Object.assign(this, {
name,
host,
port,
logger,
reconnect,
reconnectTimeout,
connected: false,
});
this.connect();
}
/**
* Connect the socket - called internally by the constructor
*/
connect() {
const { name, host, port, reconnect, reconnectTimeout, logger } = this;
logger.debug(`${name} connecting to ${host}:${port} ... `);
const client = new net.Socket();
this.client = client;
client.connect({ host, port }, () => {
logger.info(`${name} connected successfully to ${host}:${port}`);
this.connected = true;
this.emit('connected');
});
client.on('data', (chunk) => {
const data = chunk.toString();
logger.debug(`${name} received data from ${host}:${port}:`, data);
this.emit('data', data);
});
client.on('end', () => {
logger.debug(`${name} disconnected from ${host}:${port}`);
this.connected = false;
this.emit('disconnected');
});
client.on('close', () => {
this.connected = false;
if (reconnect) {
this.timer = setTimeout(() => this.connect(), reconnectTimeout);
}
});
}
/**
* Disconnect the socket manually, will not reconnect
*/
end() {
const { name, host, port, client, connected, logger } = this;
if (client && connected) {
client.end();
this.reconnect = false;
client.destroy();
logger.warn(
`${name} shut down and destroyed connection to ${host}:${port}`,
);
}
}
/**
* Primary API method - turns the specified relay on or off
*
* @param {number} relayNum Relay number, must be between `1` and `2`, inclusive
* @param {boolean} on [default: `true`] If `true`, turns relay on, if `false`, turns relay off. Any other value (undefined/null/empty string) does nothing (returns immediately)
*/
setRelayState(relayNum = 1, on = true) {
const { name, host, port, logger, client, connected } = this;
if (on === undefined || on === null) {
return;
}
if (!connected) {
logger.warn(
`${name} not connected to ${host}:${port} yet, cannot send relay command`,
);
}
if (relayNum < 1 || relayNum > NUM_RELAYS) {
logger.warn(
`${name}: Invalid relay number ${relayNum} for ${host}:${port}`,
);
return;
}
logger.debug(
`${name} setting relay ${relayNum} to ${
on ? 'ON' : 'OFF'
} on ${host}:${port}`,
);
client.write(`${on ? RELAY_ON : RELAY_OFF}${relayNum}`);
}
}
@josiahbryan
Copy link
Author

Example Usage:

import { Wangdd22RelayClient } from './Wangdd22RelayClient';

const client = new Wangdd22RelayClient();

client.on('connected', () => {
	client.setRelayState(1, true);
	client.setRelayState(2, false);

	setTimeout(() => client.setRelayState(1, false), 1000);
	setTimeout(() => client.setRelayState(2, true), 2000);
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment