u
This commit is contained in:
53
todo___/wss-client-example/example.js
Normal file
53
todo___/wss-client-example/example.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import { TischlerClient } from './lib.js';
|
||||
|
||||
// Configuration (Replace with your actual values or set ENV vars)
|
||||
// Example: SERVER_URL=ws://localhost:3000 API_KEY=k_... node example.js
|
||||
const SERVER_URL = process.env.SERVER_URL || 'wss://dash.bosewolf.de/agentapi/';
|
||||
const API_KEY = process.env.API_KEY || 'YOUR_API_KEY_HERE';
|
||||
|
||||
if (API_KEY === 'YOUR_API_KEY_HERE') {
|
||||
console.error('Please set API_KEY environment variable or edit example.js');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new TischlerClient(SERVER_URL, API_KEY);
|
||||
|
||||
client.onAuthenticated = () => {
|
||||
// Determine random values for demo
|
||||
const temp = 20 + Math.random() * 5;
|
||||
const humidity = 40 + Math.random() * 20;
|
||||
|
||||
// Example 1: Numeric Data (e.g. Temperature)
|
||||
// Note: The 'device' id will be prefixed by the server with your Agent's prefix.
|
||||
const readings = [
|
||||
{
|
||||
device: 'sensor-1',
|
||||
channel: 'temperature',
|
||||
value: temp
|
||||
},
|
||||
{
|
||||
device: 'sensor-1',
|
||||
channel: 'humidity',
|
||||
value: humidity
|
||||
},
|
||||
// Example 2: Generic JSON Data (e.g. Status object)
|
||||
{
|
||||
device: 'sensor-1',
|
||||
channel: 'status',
|
||||
data: { status: 'ok', battery: '95%', fw: '1.2.0' } // 'data' field for JSON
|
||||
}
|
||||
];
|
||||
|
||||
client.sendReadings(readings);
|
||||
|
||||
// Close after a standardized delay to ensure ACK is received
|
||||
setTimeout(() => {
|
||||
console.log('Done. Closing connection.');
|
||||
client.close();
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
// Start
|
||||
client.connect().catch(err => {
|
||||
console.error('Failed to connect:', err);
|
||||
});
|
||||
130
todo___/wss-client-example/lib.js
Normal file
130
todo___/wss-client-example/lib.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import WebSocket from 'ws';
|
||||
|
||||
/**
|
||||
* A simple client for the TischlerCtrl WebSocket API.
|
||||
*/
|
||||
export class TischlerClient {
|
||||
/**
|
||||
* @param {string} url - The WebSocket server URL (e.g., 'ws://localhost:3000')
|
||||
* @param {string} apiKey - Your Agent API Key
|
||||
*/
|
||||
constructor(url, apiKey) {
|
||||
this.url = url;
|
||||
this.apiKey = apiKey;
|
||||
this.ws = null;
|
||||
this.authenticated = false;
|
||||
this.onAuthenticated = null; // Callback
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the WebSocket server.
|
||||
* @returns {Promise<void>} Resolves when connected (but not yet authenticated)
|
||||
*/
|
||||
connect() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ws = new WebSocket(this.url);
|
||||
|
||||
this.ws.on('open', () => {
|
||||
console.log('[Client] Connected to server.');
|
||||
this.authenticate();
|
||||
resolve();
|
||||
});
|
||||
|
||||
this.ws.on('message', (data) => this.handleMessage(data));
|
||||
|
||||
this.ws.on('error', (err) => {
|
||||
console.error('[Client] Connection error:', err.message);
|
||||
reject(err);
|
||||
});
|
||||
|
||||
this.ws.on('close', () => {
|
||||
console.log('[Client] Disconnected.');
|
||||
this.authenticated = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send authentication message.
|
||||
*/
|
||||
authenticate() {
|
||||
console.log('[Client] Authenticating...');
|
||||
this.send({
|
||||
type: 'auth',
|
||||
apiKey: this.apiKey
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send sensor readings.
|
||||
* @param {Array<Object>} readings - Array of reading objects
|
||||
* @example
|
||||
* client.sendReadings([
|
||||
* { device: 'temp-sensor-1', channel: 'temp', value: 24.5 },
|
||||
* { device: 'temp-sensor-1', channel: 'config', data: { mode: 'eco' } }
|
||||
* ]);
|
||||
*/
|
||||
sendReadings(readings) {
|
||||
if (!this.authenticated) {
|
||||
console.warn('[Client] Cannot send data: Not authenticated.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[Client] Sending ${readings.length} readings...`);
|
||||
this.send({
|
||||
type: 'data',
|
||||
readings: readings
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming messages.
|
||||
*/
|
||||
handleMessage(data) {
|
||||
try {
|
||||
const message = JSON.parse(data.toString());
|
||||
|
||||
switch (message.type) {
|
||||
case 'auth':
|
||||
if (message.success) {
|
||||
this.authenticated = true;
|
||||
console.log(`[Client] Authenticated as "${message.name}" (Prefix: ${message.devicePrefix})`);
|
||||
if (this.onAuthenticated) this.onAuthenticated();
|
||||
} else {
|
||||
console.error('[Client] Authentication failed:', message.error);
|
||||
this.ws.close();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ack':
|
||||
console.log(`[Client] Server acknowledged ${message.count} readings.`);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error('[Client] Server error:', message.error);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('[Client] Received:', message);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Client] Failed to parse message:', err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to send JSON object.
|
||||
*/
|
||||
send(obj) {
|
||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close connection.
|
||||
*/
|
||||
close() {
|
||||
if (this.ws) this.ws.close();
|
||||
}
|
||||
}
|
||||
13
todo___/wss-client-example/package.json
Normal file
13
todo___/wss-client-example/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "wss-client-example",
|
||||
"version": "1.0.0",
|
||||
"description": "Example client for TischlerCtrl WebSocket API",
|
||||
"main": "lib.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node example.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user