jens-maus / node-unifi Goto Github PK
View Code? Open in Web Editor NEWNodeJS class for querying/controlling a UniFi-Controller (UDM-Pro, UDM-SE, UDM, UDR, UDW, CloudKey Gen1/Gen2) from Ubiquiti (www.ui.com)
License: MIT License
NodeJS class for querying/controlling a UniFi-Controller (UDM-Pro, UDM-SE, UDM, UDR, UDW, CloudKey Gen1/Gen2) from Ubiquiti (www.ui.com)
License: MIT License
I am trying to find out where my bug/error/issue is.
my tool is using node-unifi and since I upgraded to a new version of the controller 8.02 I get an error 401
I tried multiple things: username, password, creating new users but always an error 401
so to eliminate things I installed a fresh virtual server machine and installed npm and the node-unifi tool with the sample script first step.
also here
ERROR: AxiosError: Request failed with status code 401
To further see if it is my setup I used a python and php testscript which was working fine.
So it seems that after an upgrade of 7.x to 8.02 there is something different now where other modules/classes in another language still work.
I understand that 8.02 is still early access (normally I do not upgrade it but my finger was too quick pressing the mouse .. )
tried to update node-unifi but it might be an axios issue? But I do not see if somebody else is experiencing same issue.
TypeError: _self.listRadiusAccounts is not a function at new Controller (/home/pi/nodejs/node_modules/node-unifi/unifi.js:1311:9) at module.exports (/home/pi/nodejs/presencenotifier.js:7:19)
I receive this error after upgrade to version 1.2.1
Hi there,
I tried the example, but I don't get any data from the controller.
Anyone an idea what's wrong?
This is the Output:
--> node app.js
login: true
listen: true
ctrl.connect
ctrl.pong
ctrl.pong
ctrl.pong
ctrl.pong
ctrl.pong
ctrl.pong
ctrl.pong
ctrl.pong
ctrl.pong
The API-Example works.
THANKS.
Hallo Jens,
Ich verzweifle ... kann es sein, dass in der Funktion getAlarms der Parameter „archived“
nicht ausgewertet wird?
Ich habe gefühlt alles versucht um nur die aktuellen Alarme zu bekommen ... leider bekommen ich nur meine 1411 archivierten + 2 neue :-)
Hier ist mein Original-Post (leider ohne Hilfe :-)) https://forum.iobroker.net/post/546561
Herzlichen Dank
Jörg
Ubiquity released a new piece of hardware, the Cloud Key 2 and also the brand new Unifi Protect, which maybe will replace Unifi Video in the long run.
Are there plans to support Unifi Protect?
Hi,
Great job I'm a noob with nodejs
Could you give me an exemple for authorize guest ?
I don't know how I can call this function.
Thanks
I have a launchd script that runs every two hours to turn POE on and off. This script runs on my UniFi USW-Pro-24-PoE without it power cycling the entire switch; however, running the same script on the USW-Flex causes it to restart the entire switch. Is this unavoidable, or is there a different command I could use when interacting with the USW-Flex via API? I am using the script provided in this library.
https://github.com/jens-maus/node-unifi/blob/master/examples/poe-switch-onoff.js
Hi,
When I call authorized guest with my external controller for the guest can access to internet after 25 second.
It's work faster with local hosted controller
I tryed to send ap mac address for faster authorization but nothing change...
controller.authorizeGuest(site, mac, duration, function(err, data) {
console.log(err, data);
}, undefined, undefined, undefined, ap);
});
I don't know if I correct ? I can not find a solution
If I use unifi guest portal its very fast.
thanks
I'm trying to write a script that pulls event logs. I plan to automate it. I have everything working but I want to make sure there is some error handling so if something goes wrong I can have a log of it. However, when I try to log in with wrong credentials I never get a callback. The code below prints "Good" when the credentials are OK, but doesn't print "Bad" when they are not.
const unifi = require('node-unifi');
const controller = new unifi.Controller({host: 'XXXXXX', port: 443, sslverify: false});
const fs = require('fs');
const workflow = controller.login('XXXXX', 'XXXXX')
.then(result => {
console.log("Good");
}).catch(err => {
console.log("Bad");
});
There are two Duplicate function names in the class.
#1. This is to check Health -> https://github.com/jens-maus/node-unifi/blob/master/unifi.js#L462
#2. This is for dashboard -> https://github.com/jens-maus/node-unifi/blob/master/unifi.js#L451
Hi,
Maybe its more a feature request then a bug. But there is an second "channel" in Unifi to listen for Critical notifications.
Is there a way to listen to both of this websockets, or a flag/opts to add the needed query param.
/proxy/network/wss/s/default/events?clients=v2&critical_notifications=true
/proxy/network/wss/s/default/events?clients=v2
Dear,
as everything have been revamped on Unifi side concerning notifications and stuffs,
i'm not very sure anymore what settings need to be enabled on the Controller's interface to allow the websocket listen to eg client connect/disconnect... sometimes some of my users have issues to receive these events on UDM SE (latest version 7.3.83) but as they changed alot in event/alarm management lately, i'm not very sure... (eg on my system (software controller), all notification are disabled and i receive client connect/disconnect, but one of my users with all notification enabled receive nothing....)
could you clarify exactly what's needed ?
A simple
controller.createWLan('"testssid"','"wpapskcode"','"60a52325a959c40010401efc"','"60a52325a959c40010401efd"',true,false,false,"wpapsk","auto","auto",false,null,false,false,"[]",null)
.then(result => {
console.log("done: " + result);
}).catch(error => {
console.log("error: " + error);
});
//error: Error: Request failed with status code 400
Will give this error on the Unifi controller:
2021-10-03T01:25:59,159] WARN sanitize - Unsupported format exists in WlanConf payload={name="testssid", usergroup_id="60a52325a959c40010401efc", wlangroup_id="60a52325a959c40010401efd", enabled=true, hide_ssid=false, is_guest=false, security=wpapsk, wpa_mode=auto, wpa_enc=auto, vlan_enabled=false, uapsd_enabled=false, schedule_enabled=false, schedule=null, x_passphrase="wpapskcode"}
I have tried even just to use the basic settings from the documentation, but it seems to give the same error. I am on controller Buildatag_5.14.23_13880
WebSocket interval crash on line 2922 when connection is lost.
Error: WebSocket is not open: readyState 0 (CONNECTING)
File "/node_modules/ws/lib/websocket.js", line 441, col 13, in WebSocket.send
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
File "/node_modules/node-unifi/unifi.js", line 2922, col 16, in Timeout._onTimeout
this._ws.send('ping');
File "node:internal/timers", line 559, col 17, in listOnTimeout
File "node:internal/timers", line 502, col 7, in processTimers
How do you catch this exception?
State value to set for "unifi.0.default.clients.e8:db:xx:xx:xx:xx.noted" has to be type "boolean" but received type "string"
using Unifi Adapter in ioBroker will lead to the warning message above.
This will spam the log.
ERROR startListening: Error: Request failed with status code 403
at createError (/var/www/html/plugins/unifi/resources/node_modules/node-unifi/node_modules/axios/lib/core/createError.js:16:15)
at settle (/var/www/html/plugins/unifi/resources/node_modules/node-unifi/node_modules/axios/lib/core/settle.js:17:12)
at /var/www/html/plugins/unifi/resources/node_modules/node-unifi/node_modules/axios-cookiejar-support/lib/interceptors/response.js:83:25
at new Promise ()
at responseInterceptor (/var/www/html/plugins/unifi/resources/node_modules/node-unifi/node_modules/axios-cookiejar-support/lib/interceptors/response.js:82:9)
at /var/www/html/plugins/unifi/resources/node_modules/node-unifi/node_modules/axios-cookiejar-support/lib/index.js:130:67
at processTicksAndRejections (internal/process/task_queues.js:95:5) {
config: {
url: 'https://192.168.1.8/proxy/network/dl/firmware/bundles.json',
method: 'post',
data: '{}',
headers: {
Accept: 'application/json, text/plain, */*',
'X-CSRF-Token': 'aaaaaaa-9306-4bdf-9b45-151134d8c7df',
'Content-Type': 'application/json',
Cookie: 'TOKEN=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.eyJ1c2VySWQiOiIwNWE5YWJiMi1hYmE1LTQ1YjMtYTc2MS0wOWJlYjQ2YWU2NDEiLCJjc3JmVG9rZW4iOiIwYjdhZDU2ZS1hYmU5LTQ3N2MtYjRjNS0wNDllZTU4MzQ4ZTUiLCJqdGkiOiIwZmFkN2E5Ni1hYmNkLTQ3YjAtODZmNy1iYjEzMWM5MjYxODYiLCJwYXNzd29yZFJldmlzaW9uIjoxNjEyMzEwNjQ2LCJpYXQiOjE2NTIyMjE1MDgsImV4cCI6MTY1MjIyNTEwOH0.bWzGkzRyb51_PGuZsa7oexvP9f-8ORtdNfqNcnky8BM',
'User-Agent': 'axios/0.21.4',
'Content-Length': 2
},
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
withCredentials: true,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
httpsAgent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 443,
protocol: 'https:',
options: [Object],
requests: {},
sockets: {},
freeSockets: [Object],
keepAliveMsecs: 1000,
keepAlive: true,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 0,
maxCachedSessions: 100,
_sessionCache: [Object],
[Symbol(kCapture)]: false
},
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
jar: CookieJar {
rejectPublicSuffixes: true,
enableLooseMode: false,
allowSpecialUseDomain: false,
store: { idx: {
'192.168.1.8': {
'/': {
TOKEN: Cookie="TOKEN=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.eyJ1c2VySWQiOiIwNWE5YWJiMi1hYmE1LTQ1YjMtYTc2MS0wOWJlYjQ2YWU2NDEiLCJjc3JmVG9rZW4iOiIwYjdhZDU2ZS1hYmU5LTQ3N2MtYjRjNS0wNDllZTU4MzQ4ZTUiLCJqdGkiOiIwZmFkN2E5Ni1hYmNkLTQ3YjAtODZmNy1iYjEzMWM5MjYxODYiLCJwYXNzd29yZFJldmlzaW9uIjoxNjEyMzEwNjQ2LCJpYXQiOjE2NTIyMjE1MDgsImV4cCI6MTY1MjIyNTEwOH0.bWzGkzRyb51_PGuZsa7oexvP9f-8ORtdNfqNcnky8BM; Path=/; Secure; HttpOnly; hostOnly=true; aAge=10ms; cAge=22ms"
}
}
} },
prefixSecurity: 'silent',
_cloneSync: [Function (anonymous)],
_importCookiesSync: [Function (anonymous)],
getCookiesSync: [Function (anonymous)],
getCookieStringSync: [Function (anonymous)],
getSetCookieStringsSync: [Function (anonymous)],
removeAllCookiesSync: [Function (anonymous)],
setCookieSync: [Function (anonymous)],
serializeSync: [Function (anonymous)]
},
maxRedirects: 0,
validateStatus: [Function: validateStatus]
},
request: ClientRequest {
_events: [Object: null prototype] {
error: [Function: handleRequestError],
prefinish: [Function: requestOnPrefinish]
},
_eventsCount: 2,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 2,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
secureConnecting: false,
_SNICallback: null,
servername: false,
alpnProtocol: false,
authorized: false,
authorizationError: 'DEPTH_ZERO_SELF_SIGNED_CERT',
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 9,
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_readableState: [ReadableState],
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: [TLSWrap],
_requestCert: true,
_rejectUnauthorized: false,
parser: null,
_httpMessage: null,
timeout: 0,
[Symbol(res)]: [TLSWrap],
[Symbol(verified)]: true,
[Symbol(pendingSession)]: null,
[Symbol(async_id_symbol)]: -1,
[Symbol(kHandle)]: [TLSWrap],
[Symbol(kSetNoDelay)]: false,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(connect-options)]: [Object],
[Symbol(RequestTimeout)]: undefined
},
_header: 'POST /proxy/network/dl/firmware/bundles.json HTTP/1.1
' +
'Accept: application/json, text/plain, */*
' +
'X-CSRF-Token: aaaaaaa-9306-4bdf-9b45-151134d8c7df
' +
'Content-Type: application/json
' +
'Cookie: TOKEN=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.eyJ1c2VySWQiOiIwNWE5YWJiMi1hYmE1LTQ1YjMtYTc2MS0wOWJlYjQ2YWU2NDEiLCJjc3JmVG9rZW4iOiIwYjdhZDU2ZS1hYmU5LTQ3N2MtYjRjNS0wNDllZTU4MzQ4ZTUiLCJqdGkiOiIwZmFkN2E5Ni1hYmNkLTQ3YjAtODZmNy1iYjEzMWM5MjYxODYiLCJwYXNzd29yZFJldmlzaW9uIjoxNjEyMzEwNjQ2LCJpYXQiOjE2NTIyMjE1MDgsImV4cCI6MTY1MjIyNTEwOH0.bWzGkzRyb51_PGuZsa7oexvP9f-8ORtdNfqNcnky8BM
' +
'User-Agent: axios/0.21.4
' +
'Content-Length: 2
' +
'Host: 192.168.1.8
' +
'Connection: keep-alive
' +
'
',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 443,
protocol: 'https:',
options: [Object],
requests: {},
sockets: {},
freeSockets: [Object],
keepAliveMsecs: 1000,
keepAlive: true,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 0,
maxCachedSessions: 100,
_sessionCache: [Object],
[Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'POST',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '/proxy/network/dl/firmware/bundles.json',
_ended: true,
res: IncomingMessage {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 3,
_maxListeners: undefined,
socket: null,
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers: [Object],
rawHeaders: [Array],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 403,
statusMessage: 'Forbidden',
client: [TLSSocket],
_consuming: false,
_dumped: false,
req: [Circular *1],
[Symbol(kCapture)]: false,
[Symbol(RequestTimeout)]: undefined
},
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: true,
host: '192.168.1.8',
protocol: 'https:',
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
accept: [Array],
'x-csrf-token': [Array],
'content-type': [Array],
cookie: [Array],
'user-agent': [Array],
'content-length': [Array],
host: [Array]
}
},
response: {
status: 403,
statusText: 'Forbidden',
headers: {
vary: 'Origin',
'x-dns-prefetch-control': 'off',
'x-frame-options': 'SAMEORIGIN',
'strict-transport-security': 'max-age=15552000; includeSubDomains',
'x-download-options': 'noopen',
'x-content-type-options': 'nosniff',
'x-xss-protection': '1; mode=block',
'accept-ranges': 'bytes',
'content-type': 'application/json; charset=utf-8',
'x-response-time': '2ms',
'content-length': '32',
date: 'Tue, 10 May 2022 22:25:09 GMT',
connection: 'keep-alive'
},
config: {
url: 'https://192.168.1.8/proxy/network/dl/firmware/bundles.json',
method: 'post',
data: '{}',
headers: [Object],
transformRequest: [Array],
transformResponse: [Array],
timeout: 0,
withCredentials: true,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
httpsAgent: [Agent],
transitional: [Object],
jar: [CookieJar],
maxRedirects: 0,
validateStatus: [Function: validateStatus]
},
request: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 2,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [TLSSocket],
_header: 'POST /proxy/network/dl/firmware/bundles.json HTTP/1.1
' +
'Accept: application/json, text/plain, */*
' +
'X-CSRF-Token: aaaaaaa-9306-4bdf-9b45-151134d8c7df
' +
'Content-Type: application/json
' +
'Cookie: TOKEN=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.eyJ1c2VySWQiOiIwNWE5YWJiMi1hYmE1LTQ1YjMtYTc2MS0wOWJlYjQ2YWU2NDEiLCJjc3JmVG9rZW4iOiIwYjdhZDU2ZS1hYmU5LTQ3N2MtYjRjNS0wNDllZTU4MzQ4ZTUiLCJqdGkiOiIwZmFkN2E5Ni1hYmNkLTQ3YjAtODZmNy1iYjEzMWM5MjYxODYiLCJwYXNzd29yZFJldmlzaW9uIjoxNjEyMzEwNjQ2LCJpYXQiOjE2NTIyMjE1MDgsImV4cCI6MTY1MjIyNTEwOH0.bWzGkzRyb51_PGuZsa7oexvP9f-8ORtdNfqNcnky8BM
' +
'User-Agent: axios/0.21.4
' +
'Content-Length: 2
' +
'Host: 192.168.1.8
' +
'Connection: keep-alive
' +
'
',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
method: 'POST',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '/proxy/network/dl/firmware/bundles.json',
_ended: true,
res: [IncomingMessage],
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: true,
host: '192.168.1.8',
protocol: 'https:',
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype]
},
data: { message: 'Invalid CSRF Token' }
},
isAxiosError: true,
toJSON: [Function: toJSON]
}
I would like to modify this to allow changing port, specifically POE.
It looks like i need to login and use controller.getAccessDevices(site, function(err,data)), perhaps include the mac address for the switch I want just to make it easier then do a data[0].forEach(function(device)) and look for device.type == "usw". I can probably skill all this and just use the first device if I pass desired mac address though.
From there I take that device and get the _id and device_id and possibly the contents of port_overrides. I then use those two pieces of data to build a new request. It looks like while using the same cookie I pass a request to https://unifi:8443/api/s/default/rest/device/<_id> where the contents look something like
{"port_overrides":[{"port_idx":<port>,"portconf_id":"<device_id>","poe_mode":"<off|passv24|auto>"}]}
Now this is where I'm a little fuzzy. I think i may need to take device.port_overrides and modify the whole thing either adding or changing just the port_idx that I want to change. safest assumption is to probably modify the whole thing and pass it back, but my only device lab is my home network and i'm hesitant to risk taking out my whole network.
I'll be working up a fork and then a pr. I could use input on how to design the api if anyone has any suggestions. I was thinking maybe a helper class something like unifiAccessDevice that you feed a switch from getaccessdevices(site, cb, mac) to and it then validates that it is a switch and then exposes the poe. with a final controller.updateAccessDevice() maybe that writes the result back to the rest api. for now the helper class could verify that the passed device is a switch since we won't be supporting anything else and throw an exception if it gets invalid input.
This will leave an api that can be expanded to support more devices in the future, but for now will do what I need
Currently I use this library to log the dashboard data from unifi. The script runs every hour and stores the data in a mysql database. But sometimes I receive these strange error messages:
Error: Callback was already called.
at /home/stephan/nodejs/wanspeed/node_modules/async/dist/async.js:903:32
at next (/home/stephan/nodejs/wanspeed/node_modules/async/dist/async.js:5195:25)
at Request.<anonymous> (/home/stephan/nodejs/wanspeed/node_modules/node-unifi/unifi.js:1369:11)
at emitOne (events.js:101:20)
at Request.emit (events.js:191:7)
at Request.onRequestError (/home/stephan/nodejs/wanspeed/node_modules/request/request.js:884:8)
at emitOne (events.js:96:13)
at ClientRequest.emit (events.js:191:7)
at TLSSocket.socketErrorListener (_http_client.js:358:9)
at emitOne (events.js:96:13)
This is the code I use to get the dashboard data:
controller.login("user", "password", function(err) {
if (err) {
console.log('ERROR: ' + err);
return;
}
controller.getDashboard('default', function(err, client_data) {
if (err) {
console.log(err);
}
for (var i = 0; i < client_data[0].length; i++) {
//database stuff...
}
controller.logout();
}.bind({
conn: conn
}));
});
Is there a problem with my code?
The FlexHD makes it possible to control the LED colour and intensity of the status ring. It would be nice if the adapter could do this. Then you could use the beautifully shaped FlexHD as a status display. Perhaps other Unifi devices also offer this possibility. This would be a nice option .
@jens-maus You mentioned here https://github.com/iobroker-community-adapters/ioBroker.unifi/issues/28#issuecomment-626114826 that you are working on UDM-Pro / Unifi OS Support. Can you share some details on your progress?
When using the setwlansettings and createwlan functions i get a Err.InvalidPayload error. I am using version 5.6.22 of the unifiController. Have the api calls changed?
By looking through the code, the methods for updating settings in unifi, is hardwired to use POST method.
However, I have recently found out that unifi uses a PUT method, when updating things like user groups, (editUserGroup)
It should be configurable to be able to use the correct HTTP method to post / update / delete, regardless, even if json is supplied.
I am currently playing around with the websocket interface, with the long term goal of integrating this into the iobroker unifi adapter.
I noticed that the websocket interface always stops working after about an hour, i have done serveral test.
Unfortunately I do not get on now and need please support
Here you can find my test code:
https://github.com/Scrounger/ioBroker.unifi/blob/1349aa3607ef147c66b2be3cc8acebfa9dfea6bb/main.js#L1423
And here are two logs of one run, all others show the same behaviour:
unifi-ws-log-1.log
unifi-ws-log-2.log
Test setup:
UDM Pro: v3.1.16 (Unifi OS)
Network: 7.5.176
Hi
Is there any documentation on how to login to the controller when 2FA is enabled for the account?
I receive an API Error "ERROR: api.err.Ubic2faTokenRequired"
Hello,
on unifiOS lot of websockets events come from : wss://unifi/api/ws/system
with an object like :
interface IControllerEvent {
type: string;
[key: string]: unknown;
}
And it seems you just listen on : wss://unifi[/proxy/network]/wss/s/<siteName>/events
.
But on unifi ( non unifiOS ), some events are send on the "super" site wss://unifi[/proxy/network]/wss/s/super/events
( + events on the selected site ) . They are like the other SiteEvents so ( from what I saw ) :
export interface ISiteEvent {
meta: {
rc: string;
message: string;
product_line?: string;
};
data: Array<unknown>;
}
Some events like "admin login" are send on the super
site websockets .
It can be interessting to add a way to listen on them
I'm running Unifi OS 3.2.7 and Unifi 8. I just switched from the USG. I found that in order to get node-unifi to work I had to modify the source code to change the URL to not have a port number. I tried ports 80, 443 and 8443 and all failed. I can't explain it -- is this a known problem
//this._baseurl = new URL(`https://${options.host}:${options.port}`);
this._baseurl = new URL(`https://${options.host}`);
Dear,
when using these both methods, it's returning undefined :
controller.login()
.then(result => {
console.log('login: ' + result);
return controller.getFullStatus();
})
.then(result => {
console.log('getFullStatus: ' + result);
console.log('_last_results_raw: ' + controller._last_results_raw);
return controller.getDeviceNameMappings();
}) .then(result => {
console.log('getDeviceNameMappings: ' + result);
console.log('_last_results_raw: ' + controller._last_results_raw);
return controller.listen();
})....
for getDeviceNameMappings if i comment the line "result = this._last_results_raw;" it works
Hi,
I've just started looking into this, I previously used the PHP version, however I can't find any documentation of your JS build.
Generating the voucher is working as expected, which is great, however the callback/return isn't being piped? Am I missing something, or doing something incorrect?
var unifi = require('node-unifi');
var controller = new unifi.Controller(config.UBQT.Address, config.UBQT.Port);
let thisclass = {
GenerateVoucher: function()
{
controller.login(config.UBQT.User, config.UBQT.Password, function(err) {
if(err) {
console.log('ERROR: ' + err);
return;
}
controller.createVouchers(config.UBQT.Site, config.UBQT.Expiry, '', "1", "1", "WiFi Voucher via Node", config.UBQT.MaxUp, config.UBQT.MaxDown, function(err, result) {
if(err)
{
console.log(err);
return;
}
alert('data: '+ result);
controller.logout();
});
});
}
}
module.exports = thisclass;
within this function, what is "cb"?
Any help on this would be greatly appreciated.
Thank you 👍
The changes yesterday have not been applied to npm
Hi, i use to work with this great package .The webapi request with theauthorize-guest cmd was working but now i am facing an error . I try to send a post request with postman , i get alternatively api.err.LoginRequired and api.err.InvalidAccessToken when i add username and password .
Dear,
these two are missing... (compared to UniFi PHP Api)
The library is missing support for architectures using wan2 connections by default on site statistics by hardcoding the response fields.
Without wan2 support:
{
'wan-tx_bytes': 0,
'wan-rx_bytes': 0,
wlan_bytes: 25002829.956521742,
num_sta: 1027,
'lan-num_sta': 1026,
'wlan-num_sta': 1,
time: 1611252000000,
site: '5ed7f1c5d5497702636beb4f',
o: 'site',
oid: '5ed7f1c5d5497702636beb4f'
}
With wan2 support:
{
'wan-tx_bytes': 0,
'wan-rx_bytes': 0,
'wan2-tx_bytes': 770449810.1983193,
'wan2-rx_bytes': 307687031.9610084,
wlan_bytes: 25002829.956521742,
num_sta: 1027,
'lan-num_sta': 1026,
'wlan-num_sta': 1,
time: 1611252000000,
site: '5ed7f1c5d5497702636beb4f',
o: 'site',
oid: '5ed7f1c5d5497702636beb4f'
}
Thanks for this package. I've been using v1.x for more than a year and it's been working very stable. But with the most recent UnifiOS and Network application update, my simple LED updater stopped working, so I went on to update node-unifi
to v2.
But I hit a bit of an issue. This one actually took me a few hours to understand (though I have not yet been able to figure out a solution, only a workaround), and it seems to be related to #157.
I am doing the following:
const unifi = new Controller({ host, port, username, password, sslverify: false });
await unifi.login();
await unifi.setLEDOverride(id as string, value ? 'on' : 'off');
But I get a 403 error with "Invalid CSRF Token" because no token is set.
It seems login does not set a token, and if I do not have another request of some kind before doing the LED override, then it will fail due to the token not being set.
As a workaround I have the following line before setLEDOverride
:
// This is a workaround to make sure the CRSF token is updated
await unifi.getAccessDevices(mac);
This will get data for the device, that I don't need, but it will also update the CSRF token from the response.
I guess login
should take care of this or _init
should but neither seem to do that. Or maybe _request can check for it and pull it if not available.
Workaround works well for now and I'm just doing one extra request, but if you have happen to get a fix done, then I am ready to test that :)
I think this could affect many other commands if used without pulling device data before.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.