TP-Link HS110

For issues with communication ports, protocols, etc.
Post Reply
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: TP-Link HS110

Post by badidea »

About 2 seconds :-)
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

badidea, it is a huge improvement.
The code that I zipped to you takes between 150 to 230 mSec for Command 4 Get Info (if you do it repeatedly)
with the old snc

Your test program takes between 50 and 120 mSec (if you do it repeatedly)
When the HS110 is asleep it takes longer to wake it.
But I don't know how long before it goes to sleep.
Definitely more then 2 sec's, so it is easy to repeat the command whilst it is awake.

Hopefully your old version was NOT taking 2 sec's to complete a transaction.
About 2 seconds :-)
If that is so, then you have a problem.

Regard
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: TP-Link HS110

Post by badidea »

Compared to the original SNC, before the delay change from 2000 to 200 ms. I changed that back, this is a better fix. SNC behaviour is unchanged if you leave out the 3rd 'noWait' parameter.
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

The HS110 does not have a single command to check if the Relay is On / Off.
When using the command system:get_sysinfo it does have buried in the string
a statement: relay_state:1

So after some searching on stripping the string of all the unwanted char's, I wrote 2 Subs.
1 Specifically to "StripSpaces"
and another to get rid off Quotes and curly brackets.
I already replaced all the commas with LF so now the result of the command looks readable.

Code: Select all

SUB StripSpaces(Byref Text as String)
  Dim as Integer ch  = Asc(" ")           
  Dim as Integer p = 0
  For i as Integer = 0 To Len(Text) - 1
    If Text[i] <> ch Then Text[p] = Text[i] : p += 1
  Next
  Text = Left(Text, p)
End Sub

Code: Select all

Sub StripChars(Byref Text as String)
  Dim as Integer ch  = Asc(Chr(123))           
  Dim as Integer ch1 = Asc(Chr(125))           
  Dim as Integer ch2 = Asc(Chr(34))           
  Dim as Integer p = 0
  For  i as Integer = 0 TO Len(Text) - 1
    If Text[i] <> ch Then Text[p] = Text[i] : p += 1
  Next
  Text = Left(Text, p)
  Dim as String Text1 = Text
  p = 0
  For  i as Integer = 0 TO Len(Text1) - 1
    If Text1[i] <> ch1 Then Text1[p] = Text1[i] : p += 1
  Next
  Text = Left(Text1, p)
  Dim as String Text2 = Text
  p = 0
  For i as Integer = 0 TO Len(Text2) - 1
    If Text2[i] <> ch2 Then Text2[p] = Text2[i] : p += 1
  Next
  Text = Left(Text2, p)
End Sub
However now need a suggestion on how to separate all these fields into individual "Name:Value"
I did write this

Code: Select all

Sub StripStatus()
    With NetDevice(Control.Device)
        If instr(.RxData,"relay_state:") > 0 Then
            Control.Cnt = instr(.RxData,"relay_state:")
            Dim as String State = mid(.RxData,Control.Cnt + 12,1)
            Print "State = ";State
            DeviceState(Control.Device).RelayState = val(State)
        EndIf
    End With
End Sub
But to do that for every Field I am interested in is very long winded.
I am thinking along the lines of reading the string until I encounter a LF, then saving into Named entries in an Array, then stripping the Name away
from the String thus being left with a value.
Ideally I should already have a named Array and simply zoom in on the value within the string. (dreaming ?)

Any suggestions ?

Regards
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: TP-Link HS110

Post by badidea »

Dinosaur wrote:Any suggestions ?
Not yet, I was also thinking on how to untangle the JSON string in a nice way. But no concrete thoughts yet. Maybe a search on the internet for similar code is more efficient. I will study this one: https://freebasic.net/forum/viewtopic.p ... 06#p214076
Update: No luck with that. I am either too stupid for that or it is just too buggy.
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

I am working on,
Reading the string for 24 locations of LF and recording the location as LF(x).
Then using the value x-1 as Start and x as the end I have the beginning and end of each field.
Save that string(x)
Then using the : as the start and the LF as the end Read the string and assign it to each field(x)

To complex, having a glass of Red before dinner to get inspiration.

Regards
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

badidea , some progress.

Code: Select all

        Case 4  ''Decrypt data recvd and convert commas to LF''s for readability.
            If Control.PrintFlag > 0 Then Print "Step-4"
            decrypt(.RxData)
            Dim as String Temp = .Rxdata
            'StripSpaces(Temp) 
            StripChars(Temp)        'strip { } " 
            With LFCnt
                .LF(1) = 1
                Dim X as Integer
                For X = 1 to 25
                    Control.Cnt = Instr(Temp,",") 
                    If Control.Cnt > 0 Then
                            Mid(Temp,Control.Cnt) = Chr(&H0A)
                            .LF(X) = Control.Cnt
                            '                       prev.LF+1 (next LF - prev) -1 chr
                            .dString(X) = Mid(Temp,.LF(X-1)+1,(.LF(X)-.LF(X-1))-1)
                        Else
                            Exit For
                    EndIf
                Next
                .dString(X) = Right(Temp,10)    'Last Char of Temp
            End With
            For x as Integer = 1 to 25
                Print X,LFCnt.dString(X)
            Next
            .RxData = Temp
            'Print .RxData
            .StepNbr += 1
This prints
1 system:get_sysinfo:sw_ver:1.5.5 Build 181225 Rel.102720
2 hw_ver:2.0
3 type:IOT.SMARTPLUGSWITCH
4 model:HS110(AU)
5 mac:B0:BE:76:C1:B8:3C
6 dev_name:Smart Wi-Fi Plug With Energy Monitoring
7 alias: Device1
8 relay_state:1
9 on_time:78108
10 active_mode:none
11 feature:TIM:ENE
12 updating:0
13 icon_hash:
14 rssi:-24
15 led_off:0
16 longitude_i:0
17 latitude_i:0
18 hwId:A28C8BB92AFCB6CAFB83A8C00145F7E2
19 fwId:00000000000000000000000000000000
20 deviceId:80061922201888E1FBE72378A55A2C581ADF3EAA
21 oemId:6480C2101948463DC65D7009CAECDECC
22 next_action:type:-1
23 err_code:0
24
Then the next step is to assign the values to names, in this case

Code: Select all

Type dStats
    HwVer           as  String  
    Type            as  String  
    Model           as  String  
    MAC             as  String  
    DevName         as  String  
    Alias           as  String  
    RelayState      as  String  
    OnTime          as  String  
    ActiveMode      as  String  
    Feature         as  String  
    Updating        as  String  
    IconHash        as  String  
    Rssi            as  String  
    LedOff          as  String  
    Longitude       as  String  
    Latitude        as  String  
    HwId            as  String  
    FwId            as  String  
    DeviceId        as  String  
    OemId           as  String  
    NextAction      as  String  
    ErrCode         as  String  
End Type                        '=344
Dim Shared dStat(1 to 20) as dStats
In the gui code I have to be able to refer to:

Code: Select all

If val(dStat(Control.Device).RelayState) = 0 Then  blah blah
I was going to solve it by:

Code: Select all

    With LFCnt
        For X = 2 to 25
            Select case X
                Case 2	'hwver
                    Cnt = Instr(.dString(X),":")
                    If Cnt > 0 Then
                        DStat(X).HWVer =  Right(.dString(X),Len(LFCnt.dString(X)) - Cnt)
                        Print ".HWVer = ";DStat(X).HWVer
                    EndIf
                Case 3
But to do that 20 + times each time you need an update on a field seems very drawn out.
I was trying to think of a way to assign the values to a Data array (Data(x) = ...... where the name of the field is incorporated.
Sounds like Swahili ?

Regards
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

With this routine I get a segmentation fault on Case 21.
Other then the names and the value of X, the code for each case is identical.
I put some print statements in to make sure no weird values.
Also copied the Temp buffer into a file and used an Hex editor to confirm there are no control Char's
other then LF (0A).

Code: Select all

Select case X
                Case 2
                    DStat(X).HWVer =  Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".HWVer = ";DStat(X).HWVer
                Case 3
                    DStat(X).Type  =  Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Type = ";DStat(X).Type
                Case 4
                    DStat(X).Model =  Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Model = ";DStat(X).Model
                Case 5
                    DStat(X).MAC   =  Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".MAC   = ";DStat(X).MAC  
                Case 6
                    DStat(X).DevName = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".DevName=";DStat(X).DevName
                Case 7
                    DStat(X).Alias   = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Alias = ";DStat(X).Alias
                Case 8
                    DStat(X).RelayState = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Relay = ";DStat(X).RelayState
                Case 9
                    DStat(X).OnTime  = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".OnTime= ";DStat(X).OnTime
                Case 10
                    DStat(X).ActiveMode = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Active= ";DStat(X).ActiveMode
                Case 11
                    DStat(X).Feature = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Feature=";DStat(X).Feature
                Case 12
                    DStat(X).UpDating= Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".UpDating = ";DStat(X).UpDating
                Case 13                    
                    DStat(X).IconHash= Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".IconHash = ";DStat(X).IconHash
                Case 14
                    DStat(X).rssi    = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".rssi = ";DStat(X).rssi
                Case 15
                    DStat(X).LedOff  = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".LedOff= ";DStat(X).LedOff
                Case 16
                    DStat(X).Longitude= Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Longitude=";DStat(X).Longitude
                Case 17
                    DStat(X).Latitude= Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".Latitude=";DStat(X).Latitude
                Case 18
                    DStat(X).HwId    = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".HWID = ";DStat(X).HWID
                Case 19
                    DStat(X).FwId    = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".FwId = ";DStat(X).FwId 
                Case 20
                    DStat(X).DeviceID= Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".DeviceID=";DStat(X).DeviceID
                Case 21
                    Print ": Pos =";Instr(.dString(X),":")  'prints 6
                    Print "Len   =";Len(LFCnt.dString(X))   'prints 38
                    'Next line prints correct 
                    Print "Cmnd  =";Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    'Then on this line I get "Segmentation fault (core dumped)"
                    DStat(X).OEMId   = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".OEMid = ";DStat(X).OEMId
                    'If I rem out the above lines then the fault happens on the next case.
                Case 22
                    DStat(X).NextAction = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".NextAction= ";DStat(X).NextAction
                Case 23
                    DStat(X).ErrCode = Right(.dString(X),Len(LFCnt.dString(X)) - Instr(.dString(X),":"))
                    Print ".ErrCode =";DStat(X).ErrCode
                Case 24
                Case 25
            End Select
        Next
    End With
End Sub
Regards
EDIT:Changed UDT declares to include String Lengths to no avail.

Code: Select all

Type dStats
    HwVer           as  String * 4 
    Type            as  String * 20
    Model           as  String * 12 
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: TP-Link HS110

Post by badidea »

I was distracted by some other stuff, but hope to continue experiments with the HS110 this weekend.
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

badidea we all have our distractions.
Currently my wife is going through chemo therapy and that means I am away from work
and have a lot of time whilst she rests.
That is about to change next week though.

With the help of srvaldez (which you probably saw) I have modified Step 4 in the DataTxRx routine.

Code: Select all

        Case 4  ''Decrypt data recvd and extract relevant fields.
            If Control.PrintFlag > 0 Then Print "Step-4"
            decrypt(.RxData)
            Dim as string d(30)
            Dim as String s = .Rxdata
            Dim as integer i=0, j, c, l=len(s), q,r
            while i<l
               c=s[i]=58   'c = true if s[i] = 58 
               if c then
                  j=i+1
                  if s[j]=34 then 
                     q=34
                     j+=1
                  else
                     q=58
                  end if
                  while s[j]<>q andalso s[j]<>44 andalso j<l
                     if s[j]<>123 andalso s[j]<>125 then
                        If s[j] <> 34 then d(r) += chr(s[j]) 'fill string number r
                     end if
                     j+=1
                  wend
                  r+=1  'inc string number
                  i=j-1
               end if
               i+=1
            wend
            For x as Integer = 0 to 25
                LFCnt.dString(x) = d(x)
                Print X,LFCnt.dString(X)
            Next
            .RxData = s
            .StepNbr += 1
        Case 5  ''Translate to see if err > 0
Have deleted the StripChars, StripSpaces and StripStatus routines.
Removed all Print statements except for 1 just to confirm.
The idea (not a badidea :) ) is to have no print statements at all as the gui will handle that.

Regards

EDIT: Added the first 2 fields in the udt

Code: Select all

Type dStats
    Cmnd            as  String
    SubCmnd         as  String
    HwVer           as  String 
    Type            as  String 
    Model           as  String 
    MAC             as  String 
    DevName         as  String 
    Alias           as  String 
    RelayState      as  String 
    OnTime          as  String 
    ActiveMode      as  String 
    Feature         as  String 
    Updating        as  String 
    IconHash        as  String 
    Rssi            as  String 
    LedOff          as  String 
    Longitude       as  String 
    Latitude        as  String 
    HwId            as  String 
    FwId            as  String 
    DeviceId        as  String 
    OemId           as  String 
    NextAction      as  String 
    ErrCode         as  String
    Temp            as  Integer
End Type
Dim Shared dStat(1 to 20) as dStats
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

Sent a PM last night
badidea , tell me when you have had enough of this project and I will stop sending info.
Fixed Command 14.

Code: Select all

        Case 14 'Get IP from MAC
            .cmdStr = ""
            Dim as String s , IPAddr = "", Chrs
            input "MAC Address in Lower Case :"; s
            .StartTime = Times.mSec
            Dim as Long PF = FreeFile
            Open pipe "./macscan.sh " + s For Input As #PF
            Do Until Eof(PF)
                Line Input #PF, Chrs
                IPAddr += Chrs
            Loop
            .Elapsed = ((Timer - Times.CalTime) * 1000) - .StartTime 
            If Len(IPAddr) >= 13 Then
                    .DeviceIP = IPAddr
                    .cmdStr = !"{\"time\":{\"get_time\":null}}"
                    .cmnd = 9   'prove that the IP works
                Else
                    .cmdStr = ""
                    .ErrFlag = 1 :.ErrMesg = "Bad IP Reply"
            EndIf
            If Control.PrintFlag > 0 Then Print IPAddr, Len(IPAddr), .Elapsed
Took 47 sec's to complete.
Regards
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: TP-Link HS110

Post by badidea »

I lost track.
* The macscan is solved I understand?
* The JSON parser is working? Or still something better needed? I hope not, I decided that I dislike writing string parsing code.

I don't check the mail linked with PM often. I only use it for spam :-)
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

badidea the macscan is working yes.
The parser is basically manually editing the json strings, but once all the strings for each command are done
there won't be a need for any json library.
Also the code contributed by srvaldez works beautifully for all commands.

I am close to having done that.
Ignore the last update I sent to you on PM, it is still messy.

By tomorrow I will have completed all the commands and also tidied up the code to allow:
the program to run continuously
all commands available (some dangerous ones excluded)
full error checking and reporting.

That will make it a standalone application for others to use.
Only then will I convert to CGUI.

However, any code improvements you can suggest, please don't hesitate.

Regards
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: TP-Link HS110

Post by Dinosaur »

Hi All

badidea I have uploaded an update.
YFYI:
You need to edit the Addresses.txt with your Network name ,IP & password on Line 1
and the device detail on whatever line number you want to use.
For testing I copied mine onto line 20 as well.
The command for getting the IP from MAC was still trouble some.
It seems I am losing settings after the return of pipe.

So, after a Factory reset on Command 19, you have to quit as well and connect to the Smart plug directly.
When re-starting the program, it decides after not getting a response from the Router, that it will
ping the Smart Plug direct. If successful the InitNewDev routine will send the init command
and the device will reset itself to the new Network.However, it is a weak signal , so you have to be near.
The only issues (for future solving)
1: Reboot seems to act like Factory reset.
2: Time out's should be set by command. For example command 17 (Get AP's) takes a long time.
EDIT: Done but not uploaded.
3 to 10 ???

Anyhow have a play with it and look forward to any improvements you may/will have.
EDIT: Paying job will mean I won't have much time till next weekend.
Regards
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: TP-Link HS110

Post by badidea »

Dinosaur wrote:Anyhow have a play with it and look forward to any improvements you may/will have.
The project is getting a bit big to review in detail.
One small annoyance with the latest script is that if I only press <enter>, the script also quits.
Also the term "O/P" is unknown to me, although I assume that in means output.
I would personally add some more comments to the code form srvaldez. If you or someone else looks at that code, lets say, in 1 year form now and try to understand it, then good luck.
In general I would structure the program differently, but that is mostly personal preference and probably not constructive to discuss.

I think I will start my power / voltage / current logger project with the HS110 while you continue with your (GUI)-code.
Post Reply