Sunday, December 20, 2020

Plex Server inaccessible with LG TV nor Ipone

 I recently had access issue to my Plex server (running on Linux).  It was fine sometime ago, but lately everytime I tried to access it from my LG TV or my phone, they said the server was offline. I'd followed various instructions and troubleshooting I found on the Internet with no luck.  Here is the list of steps I did:

  • Ensure no VPN running on all devices and server
  • Select "Preferred" for secure connection
  • Added my private subnet in the "List of IP addresses and networks that are allowed without auth"
  • Upgrade the Plex server to the latest
  • Restart the server (e.g., "sudo service plexmediaserver restart")
  • Verify I am able to access the server through its IP (e.g, http://192.168.1.103:32400)
  • Enable DLNA server
  • Revert the Plex on TV to last publicly available version
  • Power down TV, wait 2 minutes and turn it back on

Turned out it was due to IPv6 connection was enabled on the Plex server! Once I disabled it, now I could watch my movies or stream my music to other devices.  My LG TV apparently did not support IPv6 yet.

Saturday, November 14, 2020

My Indentation configuration

 The content of $HOME/.indent.pro:


-as

-lp

-bad

-bap

-bbb

-bbo

-bli0

-nbc -c33 -cd33 -ncdb -nce -ci4 -cli0

-c4

-ncdw

-cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i8 -ip0 -l75 -lp -npcs

-nprs -npsl -saf -sai -saw -nsc -nsob -nss

-v

Sunday, July 5, 2020

Refoss Smart Wi-Fi Garage Door Opener

I bought an "add-on" device that will enable my garage door opener accessible via WiFi, as well as other automated processes as part of my home automation project last year.  I bought it on Amazon: https://www.amazon.com/Refoss-Garage-Control-Compatible-Assistant/dp/B07PM59X4J/ref=cm_cr_arp_d_product_top?ie=UTF8&th=1

It had been working perfectly since I installed it last year, but since the last few days ago it has stopped.  I thought it must be something with the networking, so I followed the procedure instructed on the manual to configure it as a new device added to the eHomeLife on my iPhone, but with no luck.  The manual says, if the WiFi LED blinks rapidly, the device has been correctly set to access our home network.  But, I have not been able to connect my app to the device.

Curious to see what was going on, I logged on to my AP router and could see the device had been assigned a valid IP address (192.168.1.55) and I could even ping it.  That's all. I then did nmap to the device to see what ports were open.  I could only see the following:

nmap -O -sO 192.168.1.55
WARNING: Disabling OS Scan (-O) as it is incompatible with the IPProto Scan (-sO)
Starting Nmap 7.80 ( https://nmap.org ) at 2020-07-05 21:44 Pacific Daylight Time
Nmap scan report for 192.168.1.55
Host is up (0.021s latency).
Not shown: 252 closed protocols
PROTOCOL STATE         SERVICE
1        open          icmp
6        open          tcp
17       open          udp
41       open|filtered ipv6
MAC Address: 48:E1:E9:51:07:50 (Chengdu Meross Technology)

Actually, if I press the WiFi button for more than 5 seconds to make it goes to configuration mode and then use the SSID of the device (it becomes an "AP" device temporarily), then open a browser to access it (at IP address 10.10.10.1, because my phone's IP was assigned 10.10.10.2), I could see basic web interface to set WIFI as well as to upgrade firmware.

Googling for "Meross" or "Refoss" firmware couldn't give anything.  The company's website also doesn't give any link or information about any firmware upgrade.  Also, What's the difference between "Meross" and "Refoss"? Is Refoss is a knock-off of Meross?  Both are Chinese companies.

Honestly, I am now tempted to develop a similar by myself, probably using ESP32 (as using Raspberry-Pi for such thing is too much for such thing, not to consider more power-hungry).

Thursday, July 2, 2020

Mac Hash Table


 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>


static unsigned char PseudoRandomHash[256] = {
     1,   87,   49,  12, 176, 178,  102, 166, 121, 193,   6,  84, 249, 230,  44,  163, 
     14, 197,  213, 181, 161,  85,  218,  80,  64, 239,  24, 226, 236, 142,  38,  200, 
    110, 177,  104, 103, 141, 253,  255,  50,  77, 101,  81,  18,  45,  96,  31,  222, 
     25, 107,  190,  70,  86, 237,  240,  34,  72, 242,  20, 214, 244, 227, 149,  235, 
     97, 234,   57,  22,  60, 250,   82,  175, 208,   5, 127, 199, 111,  62, 135,  248, 
    174, 169,  211,  58,  66, 154,  106, 195, 245, 171,  17, 187, 182, 179,   0,  243, 
    132,  56,  148,  75, 128, 133,  158, 100, 130, 126,  91,  13, 153, 246, 216,  219,
    119,  68,  223,  78,  83,  88,  201,  99, 122,  11,  92,  32, 136, 114,  52,   10, 
    138,  30,   48, 183, 156,  35,   61,  26, 143,  74, 251,  94, 129, 162,  63,  152, 
    170,   7,  115, 167, 241, 206,    3, 150,  55,  59, 151, 220,  90,  53,  23,  131, 
    125, 173,   15, 238,  79,  95,   89,  16, 105, 137, 225, 224, 217, 160,  37,  123, 
    118,  73,    2, 157,  46, 116,    9, 145, 134, 228, 207, 212, 202, 215,  69,  229, 
     27, 188,   67, 124, 168, 252,   42,   4,  29, 108,  21, 247,  19, 205,  39,  203, 
    233,  40,  186, 147, 198, 192,  155,  33, 164, 191,  98, 204, 165, 180, 117,   76, 
    140,  36,  210, 172,  41,  54,  159,   8, 185, 232, 113, 196, 231,  47, 146,  120, 
     51,  65,   28, 144, 254, 221,   93, 189, 194, 139, 112,  43,  71, 109, 184,  209}; 
     
#define N   256
     
     
int PearsonHash(uint64_t macAddr)
{
    int i;
    uint8_t h[sizeof(uint64_t)];
    int result;
    
	bzero(h, sizeof(h));
    for(i=1; i<sizeof(h); i++)
    {
		uint8_t byte = (uint8_t)(macAddr & 0xff);
        h[i] = PseudoRandomHash[(h[i-1] ^ byte) & 0xFF];
		macAddr >>= 8;
        result = h[i];
    }
    return result;
}


typedef struct
{
	uint64_t macAddr;
	int		 aid;
} RecordT;


RecordT* buildHashTable(int sz)
{
	RecordT *p = calloc(sz, sizeof(RecordT));
	return p;
}

void addRecord(RecordT* table, RecordT* rec)
{
	int slot = PearsonHash(rec->macAddr);
	table[slot].macAddr = rec->macAddr;
	table[slot].aid = rec->aid;
}

RecordT* findRecord(RecordT *table, uint64_t mac)
{
	int slot = PearsonHash(mac);
	return &table[slot];
}
     
int main()
{
    int i;
    int n;
    const uint64_t MacBase = 0x000011BABEBEEF00ULL;
    uint64_t macTable[N];
    
    for(i=0; i<N; i++)
    {
        printf(" %03u ", PseudoRandomHash[i]);
        if ((i+1)%16 == 0)
            printf("\n");
    }

	RecordT *hashTable = buildHashTable(N);

    for(i=0; i<N; i++)
    {
		uint64_t mac;
        macTable[i] = mac = MacBase + i;
	}

	for(i=0; i<N; ++i)
	{
		RecordT rec;
		rec.macAddr = macTable[i];
		rec.aid = N-i;
		addRecord(hashTable, &rec);
    }

    for(i=0; i<N; i++)
    {
        printf("%d\t %08lX: \tSlot=%u\n", i, macTable[i], PearsonHash(macTable[i]));
    }

	for(int k=0; k<N; ++k)
	{
		uint64_t mac = macTable[k];
		RecordT *p = findRecord(hashTable, mac);
    	printf("mac[%d]=%08lX \trec(%08lX,%d)\n", k, macTable[k], p->macAddr, p->aid);
	}

	free(hashTable);
}  

Wednesday, June 17, 2020

Raspberry PI 3 Model B Rev 1.2 Power Wattage

My order of USB power meter arrived a few days ago, but only today I could put it into use by plugging it in between the power supply adapter and my RPI.

The way I test the max power consumed is by creating a small C program to do infinite loop such as:

int main()
{
   while (1) {}
}

I executed it in four separate processes (open four terminals, and run the program in each one). This way I could exhaust the whole four cores in the CPU.  I also GUI desktop on the machine (LXDE).

Here what is shown by "top":




My USB power meter shows 1.17 WH, meaning in each hour it consumes 2.37 Watt or 0.00237 KWh.  If the price per kWh charged by Utility company is 12.01 cent ($0.1201/KWH), in a day I'd pay 0.00237 KWh* $0.1201/KWh * 24 hours = $‭0.006831288‬ or about $0.0068 per day.  In a month I'd pay about $0.2 minimum.

After I killed all those four infinite loop processes, the wattage did not drop.  Instead I saw it climbed to almost 2 Watt-hour.  I think over time it probably would drop back to around 2 W (idling time).

Sunday, January 26, 2020

Windows Application Development on Linux

Make sure you have installed MinGW on Linux:

sudo apt install mingw-w64 gdb-mingw-w64

Optionally, for testing purpose, install also WINE:

wine-stable wine-development wine64 wine64-development

FYI, with my recent mingw32 installation, the location for needed DLL files are in :

/usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/

ll /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/*.dll
-rwxr-xr-x 1 root root   482339 Mar 12  2018 /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/libatomic-1.dll*
-rwxr-xr-x 1 root root  1190750 Mar 12  2018 /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/libgcc_s_seh-1.dll*
-rwxr-xr-x 1 root root  1523015 Mar 12  2018 /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/libgomp-1.dll*
-rwxr-xr-x 1 root root  1393636 Mar 12  2018 /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/libquadmath-0.dll*
-rwxr-xr-x 1 root root   387526 Mar 12  2018 /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/libssp-0.dll*
-rwxr-xr-x 1 root root 16229690 Mar 12  2018 /usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/libstdc++-6.dll*

(this path should be added into PATH to make wine able to run our compiled EXE)


Example of Makefile:


APP=MyGUI
CC=x86_64-w64-mingw32-g++
WRC=x86_64-w64-mingw32-windres

$(APP).exe : $(APP).o $(APP).res
$(CC) -mwindows $(APP).o $(APP).res -o $@

$(APP).o: $(APP).c
$(CC) -mwindows -c -o $@ $<

$(APP).res : resource.rc resource.h
$(WRC) $< -O coff -o $@

clean:
rm *.res *.o $(APP).exe



The Source code:



/*-------------------------------------------------*/
/* MyGUI.c - gui hello world                    */
/* build: gcc -mwindows MyGUI.c -o MyGUI.exe */
/*-------------------------------------------------*/
#include <windows.h>

char glpszText[1024];

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

/******************************************************************************
* Main entry
******************************************************************************/
int APIENTRY WinMain(HINSTANCE hInstance, 
     HINSTANCE hPrevInstance,
     LPSTR lpCmdLine,
     int nCmdShow)
{
 wsprintf(glpszText, 
   "Hello World\nGetCommandLine(): [%s]\n"
   "WinMain lpCmdLine: [%s]\n",
   lpCmdLine, GetCommandLine() );

 WNDCLASSEX wcex; 
              
  wcex.cbSize = sizeof(wcex);
 wcex.style = CS_HREDRAW | CS_VREDRAW;
 wcex.lpfnWndProc = WndProc; /* set the callback */
 wcex.cbClsExtra = 0;
 wcex.cbWndExtra = 0;
 wcex.hInstance = hInstance;
 wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
 wcex.lpszMenuName = NULL;
 wcex.lpszClassName = "MYGUI";
 wcex.hIconSm = NULL;

 if (!RegisterClassEx(&wcex))
  return FALSE; 

 HWND hWnd;
 hWnd = CreateWindow("MYGUI", "MyGUI", WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
      CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

 if (!hWnd)
  return FALSE;

 ShowWindow(hWnd, nCmdShow);
 UpdateWindow(hWnd);

 MSG msg;
 /* main loop */
 while (GetMessage(&msg, NULL, 0, 0)) 
 {
  /* we can intercept keystrokes here too if we want */
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }

 return msg.wParam;
}


/******************************************************************************
* Main callback
******************************************************************************/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 PAINTSTRUCT ps;
 HDC hdc;
                                                 
 switch (message) 
 {
  case WM_PAINT:
   hdc = BeginPaint(hWnd, &ps);
   RECT rt;
   GetClientRect(hWnd, &rt);
   DrawText(hdc, glpszText, strlen(glpszText), &rt, DT_TOP | DT_LEFT);
   EndPaint(hWnd, &ps);
   break;

  case WM_DESTROY:
   PostQuitMessage(0);
   break;
    
  default:
   /* for everything else unhandled, do this */
   return DefWindowProc(hWnd, message, wParam, lParam);
   
 }
   
 return 0;
   
}



To run:

wine64 MyGUI.exe

If we find issue that WINE could not find some MinGW's *.dll, create soft links in WINE's system directory to the MinGW's dll:

pushd ~/.wine/drive_c/windows/system
cp -s /usr/lib/gcc/i686-w64-mingw32/7.3-win32/*.dll .
popd



To debug the EXE:

i686-w64-mingw32-gdb <EXE code>


Thursday, January 9, 2020

To list (dir command) file names sorted by their name's length


Suppose we want to list certain files (or all files in a directory), but sorted ascending by their filename's length.

The following small script meets the purpose:

First, create a PowerShell script, say, dirnamesize.ps1 with its content as below:

param (
   [string]$dirpath = "."
)

gci $dirpath | select-object name, @{Name="Nlength";Expression={$_.Name.Length}} | sort-object Nlength


Second, create a normal DOS shell file to call that PowerShell (so we don't need to open PowerShell), say, dirnamesize.cmd with the content:

set DIRPATH=%*

@if "%DIRPATH%"=="" (
    powershell dirnamesize.ps1
) else (
    powershell dirnamesize.ps1 -dirpath %DIRPATH%
)


Example:

C:\Windows>dirname *.xml

Name                        Nlength
----                        -------
Education.xml                    13
ServerRdsh.xml                   14
Enterprise.xml                   14
Professional.xml                 16
ProfessionalEducation.xml        25
ProfessionalWorkstation.xml      27