What's new

Skynet Practice displaying a world map on a webpage using an addon-api.

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

aru

Regular Contributor
I'm currently learning how to display information on a webpage through a router, but I'm not quite sure yet how to easily link it to a menu. For now, I can only access it directly by typing the URL http://192.168.168.254/user20.asp

The map below displays the latest 100 source data entries read from /tmp/mnt/usbkey/skynet/skynet.log

1710840357561.png


By displaying the locations of IP addresses on the map, users can visually understand the geographical distribution of network activities.
1710841302705.png


The following software packages are pre-installed in cmdline:

Skynet app
#amtm -> i -> 2
Python app
#opkg install python3
#opkg install python3-pip
#pip install folium
#pip install ip2geotools

Create an user20.py script in the /jffs/addons/myaddon directory:

#mkdir /jffs/addons/myaddon
#nano -w /jffs/addons/myaddon/user20.py

Please paste the following script:

Code:
#!/tmp/mnt/usbkey/entware/bin/python






import re


import folium


from collections import Counter


from ip2geotools.databases.noncommercial import DbIpCity


from concurrent.futures import ThreadPoolExecutor






# Read the last 100 lines of the file


print("Reading the last 100 lines of the file...")


with open("/tmp/mnt/usbkey/skynet/skynet.log", "r") as file:


    last_lines = file.readlines()[-100:]






# Extract source IP addresses from the last 100 lines


source_ips = []


for line in last_lines:


    match = re.search(r"SRC=([0-9.]+)", line)


    if match:


        source_ips.append(match.group(1))






# Count the occurrences of each source IP address


ip_counter = Counter(source_ips)






# Create a basic map


print("Creating a basic map...")


mymap = folium.Map(location=[30, 0], zoom_start=2)






# Function to get location information for an IP address


def get_location(ip):


    try:


        print(f"Processing IP: {ip}...")


        response = DbIpCity.get(ip, api_key='free')


        return response


    except Exception as e:


        print("Error processing IP:", ip, "-", e)


        return None






# Process IP addresses using concurrent futures


print("Processing IP addresses using concurrent futures...")


with ThreadPoolExecutor() as executor:


    futures = {executor.submit(get_location, ip): ip for ip in ip_counter.keys()}


    for future in futures:


        ip = futures[future]


        response = future.result()


        if response is not None and response.latitude is not None and response.longitude is not None:


            count = ip_counter[ip]


            radius = count * 5


            color = 'red' if count > 1 else 'blue'  # If count is greater than 1, color is red, else blue


            tooltip_text = f"IP: {ip}, Count: {count}, City: {response.city}, Country: {response.country}, Latitude: {response.latitude}, Longitude: {response.longitude}, Region: {response.region}"


            folium.CircleMarker(location=[response.latitude, response.longitude], radius=radius, color=color,


                                fill=True, fill_color=color, tooltip=tooltip_text).add_to(mymap)






# Save the map as an ASP file


print("Saving the map as an ASP file...")


mymap.save("/tmp/var/wwwext/user20.asp")






print("Processing complete.")

Please note that everyone's USB names may vary, it might be necessary to modify the path to /tmp/mnt/usbkey/skynet/skynet.log in the script. and the execution result of the addon-maps.py script will be directly saved into /tmp/var/wwwext/user20.asp. The addon provides only 20 page links, which can be checked using ls -al /www/user* to see if they are occupied.

You may need to manually adjust the following user20.py script as indicated in red according to your router environment:
#!/tmp/mnt/usbkey/entware/bin/python
.
with open("/tmp/mnt/usbkey/skynet/skynet.log", "r") as file:
.
mymap.save("/tmp/var/wwwext/user20.asp")

user1-20.asp displays red if unoccupied and white if occupied. To modify the script to output a filename other than user20.asp if it's already taken.
1710844246613.png



Change the file permissions of user20.py to make it executable.

#chmod 775 /jffs/addons/myaddon/user20.py

Then, execute the /jffs/addons/myaddon/user20.py file in cmdline. The output will be as follows:

1712015771757.png


Finally, after logging into the router, enter the user20.asp URL to view it, for example, http://192.168.168.254/user20.asp
With the above practice, I can independently add the webpage information I want to display.

Note: The ip2geotools script calls https://nominatim.openstreetmap.org/search , which is a library used for parsing geographic locations from IP addresses. I'm not certain about the free query limit of Nominatim. If you are using the free version, there may be some restrictions, such as limits on the number of IP addresses parsed per day, or there may be slower service. However, if you use the paid version, you may experience faster parsing speeds and larger quotas. If you have a large number of query requirements, please refer to the official website or documentation of https://operations.osmfoundation.org/policies/nominatim/ to get detailed information about usage restrictions.



How to mount your own webpage onto the router menu steps as below:

Edit the /tmp/menuTree.js file

#nano -w /tmp/menuTree.js

Search for the following crucial keywords highlighted in red. You'll notice that all other addon menus are uniformly integrated here (as indicated in blue).

{
menuName: "Addons",
index: "menu_Addons",

tab: [
{url: "user2.asp", tabName: "Unbound"},
{url: "user3.asp", tabName: "dn-vnstat"},
{url: "user4.asp", tabName: "connmon"},
{url: "user5.asp", tabName: "ntpMerlin"},
{url: "user7.asp", tabName: "scMerlin"},

{url: "javascript:var helpwindow=window.open('/ext/shared-jy/redirect.htm','_bl>
{url: "user8.asp", tabName: "Sitemap"},
{url: "NULL", tabName: "__INHERIT__"}
]
}

You simply need to insert your own link in a single line (as shown in green).

{
menuName: "Addons",
index: "menu_Addons",
tab: [
{url: "user20.asp", tabName: "Skynet-Maps"},
{url: "user2.asp", tabName: "Unbound"},
{url: "user3.asp", tabName: "dn-vnstat"},
{url: "user4.asp", tabName: "connmon"},
{url: "user5.asp", tabName: "ntpMerlin"},
{url: "user7.asp", tabName: "scMerlin"},
{url: "javascript:var helpwindow=window.open('/ext/shared-jy/redirect.htm','_bl>
{url: "user8.asp", tabName: "Sitemap"},
{url: "NULL", tabName: "__INHERIT__"}
]
}

After editing, simply remount the menu using the following cmdline to complete the process.

#umount /www/require/modules/menuTree.js && mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js


1710976755226.png



Done!

How to remove this script:

Remove the main script.
#rm /jffs/addons/myaddon/user20.py

Remove dependent packages, but I'm not sure if other scripts will use them. If there is any impact, please reinstall them. (Please note the removal sequence.)

pip uninstall ip2geotools
pip uninstall folium
opkg remove python3-pip
opkg remove python3

Or uninstall all dependencies installed via pip and Python. Only proceed if you are absolutely certain that no other packages rely on Python and pip.

pip freeze | xargs pip uninstall -y
opkg remove $(opkg list-installed | awk '/python/{print $1}') --force-removal-of-dependent-packages

Edit the /tmp/menuTree.js file

#nano -w /tmp/menuTree.js

Although it will automatically disappear after restarting the router, if you want to see the removal effect immediately.

Please delete the green part as below:
{
menuName: "Addons",
index: "menu_Addons",
tab: [
{url: "user20.asp", tabName: "Skynet-Maps"},
.

Remount the menu using the following cmdline to complete the process.

#umount /www/require/modules/menuTree.js && mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
 
Last edited:
This look awesome. But got following error when install python:

Code:
darkj2k@GT-AX6000:/tmp/home/root# opkg update
Downloading https://bin.entware.net/aarch64-k3.10/Packages.gz
Updated list of available packages in /opt/var/opkg-lists/entware
darkj2k@GT-AX6000:/tmp/home/root# opkg install python
Unknown package 'python'.
Collected errors:
 * opkg_install_cmd: Cannot install package python.

What should I do?
 
This look awesome. But got following error when install python:

Code:
darkj2k@GT-AX6000:/tmp/home/root# opkg update
Downloading https://bin.entware.net/aarch64-k3.10/Packages.gz
Updated list of available packages in /opt/var/opkg-lists/entware
darkj2k@GT-AX6000:/tmp/home/root# opkg install python
Unknown package 'python'.
Collected errors:
 * opkg_install_cmd: Cannot install package python.

What should I do?

Thank you for your feedback, I have corrected the proper installation command as below:

#opkg install python3
 
Thank you for your feedback, I have corrected the proper installation command as below:

After installed python3 successful.

Code:
darkj2k@GT-AX6000:/tmp/home/root# pip install folium
-sh: pip: not found

Should I reboot the router or do anything before "pip install folium"?
 
After installed python3 successful.

Code:
darkj2k@GT-AX6000:/tmp/home/root# pip install folium
-sh: pip: not found

Should I reboot the router or do anything before "pip install folium"?

I'm sorry for missing another detail, thank you for reminding me. Please install with the following command:

#opkg install python3-pip
 

Congratulations on your success! At the same time, thanks to your feedback, the installation steps have become more detailed. I'm glad I could be of assistance to you. Through this practice and understanding, you can add other informational pages yourself. 👍
 
Actually, I'm a bit confused about the part in the addon API documentation regarding integrating the plugin into the existing menu. Could you register this sample case to the menu for me to refer to? Thank you!
Unfortunately I do not have Merlin firmware on my router so I won't be able to test this

Possibly all you have to do is to just replace "/jffs/addons/my_addon/MyPage.asp" in the example code with te path to your page
 
Unfortunately I do not have Merlin firmware on my router so I won't be able to test this

Thank you! I seem to have found the method the original author mentioned for mounting the menu. I can improve the installation instructions accordingly.

# Copy menuTree (if no other script has done it yet) so we can modify it
if [ ! -f /tmp/menuTree.js ]
then
cp /www/require/modules/menuTree.js /tmp/
mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
fi

# Insert link at the end of the Tools menu. Match partial string, since tabname can change between builds (if using an AS tag)
sed -i "/url: \"Tools_OtherSettings.asp\", tabName:/a {url: \"$am_webui_page\", tabName: \"My Page\"}," /tmp/menuTree.js

# sed and binding mounts don't work well together, so remount modified file
umount /www/require/modules/menuTree.js && mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
 
Thank you! I seem to have found the method the original author mentioned for mounting the menu. I can improve the installation instructions accordingly.

You should create an easy-to-use installer script!
 
You should create an easy-to-use installer script!

Thank you for your suggestions. At the moment, I'm just beginning to understand how menus and web pages are presented on the router. I'm still figuring out how to create a user-friendly installation script, so it may take some time for me to digest and learn, and I may need some guidance along the way.
 
Thank you for your suggestions. At the moment, I'm just beginning to understand how menus and web pages are presented on the router. I'm still figuring out how to create a user-friendly installation script, so it may take some time for me to digest and learn, and I may need some guidance along the way.
We're here to help! Nice job figuring this map out! ;)
 
  • Like
Reactions: aru
We're here to help! Nice job figuring this map out! ;)

I will treasure our interactions, allowing newcomers to stand on the shoulders of giants and lead us into a router world. :)
 
The relaxed and enjoyable atmosphere you create through your discussions is truly palpable to me. I can also discern both of your formidable expertise in your respective technical fields, making it no wonder this forum is so appealing. Beyond your professional knowledge, your humorous and witty exchanges are also a delight to witness, lending the entire forum a vibrant and energetic air. To be a part of such a quality community is indeed an honor for me. Gratitude to both Viktor Jaep and SomeWhereOverTheRainBow for mutually recommending each other. 👍
 
The relaxed and enjoyable atmosphere you create through your discussions is truly palpable to me. I can also discern both of your formidable expertise in your respective technical fields, making it no wonder this forum is so appealing. Beyond your professional knowledge, your humorous and witty exchanges are also a delight to witness, lending the entire forum a vibrant and energetic air. To be a part of such a quality community is indeed an honor for me. Gratitude to both Viktor Jaep and SomeWhereOverTheRainBow for mutually recommending each other. 👍
The honor is all mine, @aru ... Happy to help with whatever @SomeWhereOverTheRainBow and I can do to bring more understanding to all this. I live by my motto...."Work hard, play harder, code even more harder!". :p Some people (like @Tech9) take this too literally, and before you know it, he's downing aircraft with SOHO router-integrated avionics. :D
 

Similar threads

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top