skydiver / ewelink-api

eWeLink API for JavaScript
https://www.npmjs.com/package/ewelink-api
MIT License
267 stars 108 forks source link

ARPtable empty #90

Open foulek57 opened 4 years ago

foulek57 commented 4 years ago

Hi,

Need your help please, i try to use the LAN mode, but i do know why the ARP file are only "[]".

Here the code :

const connection = new ewelink
    (
      {
        email: login,
        password: pass,
        region: 'eu'
      }
    );

    await connection.saveDevicesCache();
    await Zeroconf.saveArpTable({
      ip: '192.168.1.1'
    });

Can you confirm that the ip must be the ip of my router ? Or i understand wrong ?

Thanks.

ttz642 commented 4 years ago

foulek57,

What platform are you using, windows, mac or linux ?

I'm using Ubuntu 20.04 (previously 18.04) and I could never get the saveArpTable() or loadArpTable() to work so I just wrote my own bash script to create them:

#!/bin/bash
#   Create files for LAN use:
#       conf/devices-cache.json
#       conf/deviceip-table.json
#86 
TMP=`mktemp -d`
#   avahi-browse -d local _ewelink._tcp --resolve -tp

echo "Wake up devices..."
avahi-browse -d local _ewelink._tcp --resolve -tp | grep -P '^\+'
echo "Wait for devices to respond..."
sleep 10

avahi-browse -d local _ewelink._tcp --resolve -tp \
    | pcre2grep  -o2 -i  'local;eWeLink_(1000[0-9a-f]{6}).local;(192.168.1\..+);8081;' \
    | sort | tee $TMP/ewedev | gawk -F '|' -e '{print "ping  -n -c 3 "$1}' | bash

/usr/sbin/arp -an | pcre2grep -o1 -o2 -i --om-separator='|' '\? \((.*)\) at (.*) \[ether\]' | sort > $TMP/ipmac

join -t '|' $TMP/ipmac $TMP/ewedev \
    | gawk -F '|' -e 'BEGIN{print "[";li="";}{printf li"  {\n    \"ip\":\"%s\",\n    \"mac\":\"%s\"\n  }",$1,$2;li=",\n";}END{print "\n]";}' \
    > conf/arp-table.json

avahi-browse -d local _ewelink._tcp --resolve -tp | grep -P '^=' \
    | pcre2grep -o2 -o1 -i --om-separator='|' 'local;eWeLink_(1000[0-9a-f]{6}).local;(192.168.1\..+);8081;' \
    | gawk -F '|' -e 'BEGIN{print "{";li="";}{printf li"  \"%s\": \"%s\"",$2,$1;li=",\n";}END{print "\n}";}' \
    > conf/deviceip-table.json

rm -rf $TMP

bin/createDevicesCache.js

Can now set device on or off using lan.

bin/createDevicesCache.js

#!/usr/bin/node

const DEBUG = 1;
const confFileName = 'conf/devices-cache.json';

const fs = require('fs');
const ewelink = require('ewelink-api');//   https://ewelink-api.now.sh/
const soo = require("../lib/ewelib.js");
var account = soo.account();// fetch my account details
var connection = new ewelink(account);// create connection to ITLEAD server

async function main () {
    console.log("\nCreate devices cache...");
    //  await connection.saveDevicesCache();
    const devices = await connection.getDevices();
if(DEBUG)console.log("devices: " + JSON.stringify(devices,null,4));
    try {
        fs.writeFileSync(confFileName, JSON.stringify(devices, null, 2), 'utf8');
        return { status: 'ok', file: confFileName };
    } catch (e) {
        console.log('An error occured while writing JSON Object to File:',confFileName);
        return { error: e.toString() };
    }
    console.log(devices);
}

if(DEBUG)console.log("Connection: " + JSON.stringify(connection,null,4));
main();

Yo probably want to use your own code to connect to the server, I created a library of some functions, one being get account details from config file.

So replace:

const soo = require("../lib/ewelib.js");
var account = soo.account();// fetch my account details
var connection = new ewelink(account);// create connection to ITLEAD server

With your own connection to server.

foulek57 commented 4 years ago

Hello,

Using Linux on Debian 10.

Will try your script thanks for share !!

foulek57 commented 4 years ago

Hello,

Just try the script, work great to create the files.

But when i lunch the script with setDevicePowerState, i have this error :

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'ip' of undefined

Any idea ?

Do i need to place the file in a special folder ?

Thanks for your help.

ttz642 commented 4 years ago

foulek57,

I'm guessing the getDevices isn't returning all your devices and it's associated with issue #88,I had the same issue over the weekend.

foulek57 commented 4 years ago

Hum,

When i check the files, the devices are in the cache and also in the 2 file created with your script.

ttz642 commented 4 years ago

When i check the files, the devices are in the cache and also in the 2 file created with your script.

Try printing to console what is being used to find ip ?

foulek57 commented 4 years ago

So,

find this :

getDeviceIP(device) { const mac = device.extra.extra.staMac; const arpItem = this.arpTable.find( item => item.mac.toLowerCase() === mac.toLowerCase() ); return arpItem.ip; },

The error are from the return arpItem.ip

called with :

/**
   * Generate Zeroconf URL
   * @param device
   * @returns {string}
   */
  getZeroconfUrl(device) {
    const ip = this.getDeviceIP(device);
    return `http://${ip}:8081/zeroconf`;
  }
}

To generate the URL.

Called with

if (this.devicesCache) {
      return ChangeStateZeroconf.set({
        url: this.getZeroconfUrl(device),
        device,
        params,
        switches,
        state: stateToSwitch,
      });
    }

So now juste have checked the staMac adresse, they was not the good one in the ARP file !!

Have change it manually, now it's work !!

foulek57 commented 4 years ago

So finally, the problem is that the wrong Mac address are put to the ip address, the ip address of my basic are 192.168.1.37 But the Mac address in the arp file are they of the 192.168.1.35

See picture.

IMG_20200604_000913

Do know why, need to search the reason, but now I go sleep, it's time in France :)

To be continued...

ttz642 commented 4 years ago

Have the devices changed IP address due to the DHCP server in the wifi?

I have made all my devices get fixed addresses.

I see the IP .35 & .37 have the same mac address, have you got duplicate mac address in two devices or is the arp cache need flushing?

sudo ip -s -s neigh flush all
sudo -d 192.168.1.35
sudo -d 192.168.1.37
foulek57 commented 4 years ago

Hi,

Have do the flush all cmd then sudo arp -s 192.168.1.(all the ip)

lunch the script, same problem The arp -a command give the wrong mac adress

ttz642 commented 4 years ago

The arp -a command give the wrong mac adress

I'd doubt the arp command is giving wrong data, it's been in use of billions of devices.

I'm guessing you've got two devices with the same MAC address, it does happen, not often but there simply aren't enough MAC addresses for manufacturers.

I did once have two NCD X-window terminals with the same MAC, had to reprogram the NVM with different MAC.

try:

$ /usr/sbin/arp -a
. . .
ESP_8F85DD (192.168.1.233) at d8:f1:5b:8f:85:dd [ether] on wlp2s0

$ sudo nmap -PU 192.168.1.233  <== problem IP addresses
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-04 15:55 BST
Nmap scan report for ESP_8F85DD (192.168.1.233)
Host is up (0.019s latency).
Not shown: 999 closed ports
PORT     STATE SERVICE
8081/tcp open  blackice-icecap
MAC Address: D8:F1:5B:8F:85:DD (Espressif)

Nmap done: 1 IP address (1 host up) scanned in 2.65 seconds

$ sudo nmap -PU 192.168.1.0/24  <== Scan sub net
foulek57 commented 4 years ago

Hi,

Have all Sonoff with DHCP fixed with the Mac address and also the cache data have the same Mac address, so the 2 devices have different Mac address.

Have do a script to read the json' file of the cache to output the Mac address of each device, and compare to the device up json' file to output a json' file with ip:Mac

So now that work.

The script are in php because I'm not good with bash script, will share it and if you want you can adapt it in bash or JavaScript

ttz642 commented 4 years ago

foulek57,

There's something up with your system if arp is returning the wrong mac address for ip address.

foulek57 commented 4 years ago

Hey

Just do tilt I'm my head ! I'm so idiot !

The Mac address of the 2 devices, are the Mac address of the wifi repeater !

All the connected devices have the same Mac address see below

IMG_20200604_203739

So arp are not compatible if the Sonoff are connected with a wifi repeater.

Think that the best way are to pick the Mac address in the cache json' and attribute it to the deviceid, then use the device ip json' to attribute the Mac address to the ip. Will give example in 2-3 hour, now I'm on mobile phone

ttz642 commented 4 years ago

I think it would be better if we simply did the deviceID to IP lookup in one, currently the deviceID is used to lookup the MAC address which is then used to lookup the IP address.

I made a suggestion to this here https://github.com/skydiver/ewelink-api/issues/57#issuecomment-573321151

It's what I did to start with then modified to create the json as currently used.

skydiver commented 4 years ago

Hello @ttz642

Thank you for all your comments and help.

I agree with you, the ideal scenario will be a file with the following format:

{
  "1000xxxxxx": "192.168.1.233",
  "1000xxxxxx": "192.168.1.220",
  "1000xxxxxx": "192.168.1.238",
  "1000xxxxxx": "192.168.1.237",
  "1000xxxxxx": "192.168.1.202",
  "1000xxxxxx": "192.168.1.249",
  "1000xxxxxx": "192.168.1.227"
}

I will try to take a look to your suggestion, is this the right package https://www.npmjs.com/package/avahi-browse?

The arp table method always worked for me, but i understand every network it's a different world, so i'm happy to have different ways of making the cache files.

ttz642 commented 4 years ago

I will try to take a look to your suggestion, is this the right package https://www.npmjs.com/package/avahi-browse?

I was just using the command line version in ubuntu, I know you want everything in js.

Instantiate the class with:

const browser = new AVAHI_BROWSE('_ewelink._tcp');

And it just returns the ewelink compatible devices as json structure:

{ service_name: 'eWeLink_10006c40ec',
  target:
   { service_type: '_ewelink._tcp',
     domain: 'local',
     host: '192.168.1.238',
     hostname: 'eWeLink_10006c40ec.local',
     port: '8081' } }

If you don't specify the service type it defaults to '_http._tcp.' and doesn't find the ewelink devices. Documentation is sparse had to look at the code to figure out what I needed to do.

Tested on ubuntu 20.04