PYTHON SCRIPT: JS8 RSS NEWS READER

I started working on a project with my friend Justin in 2022, we were able to put several months in and conducted a lot of experiments.

To learn more about what we have been trying to do: RADENGINEERING.TECH

We haven’t given up on the project, but we both have to make money, to get by, and we don’t have the time to put much more into it …

In order to promote this project, I was asked to build a simple RSS newsreader, operating using JS8 protocol, accessing some of the software’s API and using log files for monitoring. Not a lot of code allowed for a pretty cool experience, where headlines were being sent using CB RADIO, 11M, 27.245 MHZ.

Do with it what you will.

SQL Code (for MySQL): https://planetarystatusreport.com/RSS.TXT

https://youtube.com/watch?v=1nxT5ZXOt-c
#Daniel John Sullivan, CEO, Rad Engineering, 3/23/22

#This is a news agent/script, a prototype
#Service, utilizing JS8 as a proxy agent
#to encode messages and decode from our
#transceiver

#JS8 Callsign for this service - N3W5 or NEWS ...

#1. monitor directed file for requests
#2. respond to new requests
#3. grab RSS feed data

#there are a few python modules that need
#to be installed: maidenhead, feedparser, bs4
# anyascii, and perhaps one or two others
# just be comfortable using pip3 to install
# these other modules / libraries

from __future__ import print_function

import os
import feedparser
import os.path, time
import json
import math
import time
import maidenhead as mh
import urllib.parse as pr
import xml.etree.ElementTree as ET
from bs4 import BeautifulSoup as BS
from requests import get
from os.path import exists
from socket import socket, AF_INET, SOCK_STREAM
from decimal import Decimal
from datetime import datetime, date, timedelta
from anyascii import anyascii
import mysql.connector

### globals ###

DPath = "/home/pi/.local/share/JS8Call/DIRECTED.TXT"

# server/port info for connecting to the JS8 Call application
# while it is running, it can act as a message server/proxy
# for your radio kit ... we are still figuring out the API
# so right now, it's just 'send' capabilities we are using
# - DJS, 3/19/22

JS8Server = "127.0.0.1"
JS8PortNum = 2442

#make sure you open port 2442 prior to opening JS8 application
#ubuntu command: sudo ufw allow 2442
server = (JS8Server, JS8PortNum)

servern = "localhost";
portn = 3306
usern = "DBUSER";
passw = "DBPASSWORD";
dbn = "DBNAME";

#mode 1: just top stories from each feed, sent just once
#mode 2: active engagement mode
#mode 3: just one service

newsServiceM3 = "ONION"

newsMode = 3

bigSleep = 90

### end of globals ###

def from_message(content):
	try:
		return json.loads(content)
	except ValueError:
		return {}

def to_message(typ, value='', params=None):
	if params is None:
		params = {}
	return json.dumps({'type': typ, 'value': value, 'params': params})

class JS8Client(object):

	def __init__(self):
		self.PttON = False
		self.LastPtt = datetime.now()

	def process(self, message):
		typ = message.get('type', '')
		value = message.get('value', '')
		params = message.get('params', {})
		if not typ:
			return
		if typ in ('RX.ACTIVITY',):
			# skip
			return

		if value and typ == "RIG.PTT":
			if value == "on":
				self.PttON = True
				self.LastPtt = datetime.now()
				print("PTT ON")
			if value == "off":
				self.PttON = False
				print("PTT OFF")
				
	def send(self, *args, **kwargs):
		params = kwargs.get('params', {})
		if '_ID' not in params:
			params['_ID'] = '{}'.format(int(time.time()*1000))
			kwargs['params'] = params
		message = to_message(*args, **kwargs)
		self.sock.send((message + '\n').encode()) # remember to send the newline at the end :)

	def GetStationStatus(self):
		self.sock = socket(AF_INET, SOCK_STREAM)
		self.sock.connect(server)
		self.connected = True
		try:			
			self.send("TX.GET_TEXT", "")
			content = self.sock.recv(65500)
			message = json.loads(content)
			
			typ = message.get('type', '')
			value = message.get('value', '')
			
			if typ == "TX.TEXT":
				vt = value.strip()
				if len(vt) < 1:
					return "OPEN"
				else:
					return "CLOSED"
			else:
				return "CLOSED"
		except:
			return "CLOSED"
		finally:
			self.sock.close()

	def SendToJS8(self, JS8Message):
		self.sock = socket(AF_INET, SOCK_STREAM)
		self.sock.connect(server)
		self.connected = True
		try:			
			self.send("TX.SEND_MESSAGE", JS8Message)
			content = self.sock.recv(65500)
			print(content)
		except:
			print("Error sending message to JS8 via API.")
		finally:
			self.sock.close()

	def close(self):
		self.connected = False

#### END OF CLASS DEFINITION FOR JS8 API INTERFACE ####

def GetArt(number):
	# Connect with the MySQL Server
	cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
	qry = "select ARTICLE, SOURCE, LINK from RSS where ID = %s" % (number)
	cur = cnx.cursor(buffered=True)
	cur.execute(qry)
	retRes = cur.fetchall()
	cnx.close()
	return retRes[0]

def GetTopHourly(source):
	# Connect with the MySQL Server
	cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
	qry = "select ID, TITLE, PUBLISHED, SOURCE, length(ARTICLE) as LOF from RSS where SOURCE = '%s' order by PUBLISHED desc limit 1" % source
	cur = cnx.cursor(buffered=True)
	cur.execute(qry)
	retRes = cur.fetchall()
	cnx.close()
	return retRes

def GetTop(source, number):
	# Connect with the MySQL Server
	cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
	qry = "select ID, TITLE, PUBLISHED, SOURCE, length(ARTICLE) as LOF from RSS where SOURCE = '%s' order by PUBLISHED desc limit %s" % (source, number)
	cur = cnx.cursor(buffered=True)
	cur.execute(qry)
	retRes = cur.fetchall()
	cnx.close()
	return retRes

def AlreadySaved(link):
	# Connect with the MySQL Server
	cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
	qry = "select ID from RSS where LINK = '" + link + "'"
	cur = cnx.cursor(buffered=True)
	cur.execute(qry)
	cur.fetchall()
	rc = cur.rowcount
	cnx.close()
	if rc > 0:
		return True
	else:
		return False

def SaveRSS(source, title, link, published, article):

	tit = title.replace("'", "''")

	clean_text = anyascii(article)
	
	art = str(clean_text)

	art = art.replace("'", "''")
	
	if len(art) > 5000:
		art = art[0:5000]
	
	cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
	
	cur = cnx.cursor()

	qry = """
	INSERT INTO RSS
	(SOURCE, 
	LINK, 
	TITLE, 
	PUBLISHED, 
	ARTICLE) 
	VALUES 
	(%s,%s,%s,%s,%s)
	""" 
	
	val = (source, link, tit, published, art)

	cur.execute(qry, val)

	cnx.commit()
	
	cnx.close()

def GrabRSS(RssURL, SourceName):

	hdrs = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}

	NewsFeed = feedparser.parse(RssURL)

	for na in NewsFeed.entries:

		try:
			print(na.title)
			print(na.link)
			print(na.published)
			print(na.published_parsed)
		except:
			continue
			
		if AlreadySaved(na.link):
			continue

		print("*************************")

		response = get(na.link, None, headers=hdrs)

		print(na.keys())

		soup = BS(response.content, 'html.parser')
	
		txtChunk = ""

		for data in soup.find_all("p"):
			txtval = data.get_text()
			txtval = txtval.strip()
			txtarr = txtval.split()
		
			if len(txtarr) == 1:
				continue
		
			if "posted" in txtval and ("hours" in txtval or "days" in txtval) and len(txtarr) == 4:
				continue
			
			if txtval == "No Search Results Found":
				continue
			
			if txtval == "Terms of Service":
				continue
		
			if txtval == "Advertise with us":
				continue
			
			if txtval == "Media Inquiries":
				continue

			txtChunk += " " + txtval + "\n"
	
		tyr = na.published_parsed[0]
		tmn = na.published_parsed[1]
		tdy = na.published_parsed[2]
		thr = na.published_parsed[3]
		tmi = na.published_parsed[4]
		tsc = na.published_parsed[5]
	
		ptms = "%s-%s-%s %s:%s:%s" % (tyr, tmn, tdy, thr, tmi, tsc)	
	
		SaveRSS(SourceName, na.title, na.link, ptms, txtChunk.strip())
	
		print(txtChunk.strip())

def debugHere():
	input("Press enter to continue ...")

def clearConsole():
	command = 'clear'
	if os.name in ('nt', 'dos'):  # If Machine is running on Windows, use cls
		command = 'cls'
	os.system(command)

def TopStoriesFrom(news, numof):
	
	s = JS8Client()

	ti = GetTop(news, numof)
	
	for t in ti:
			
		pubarr = str(t[2]).split()	
		pubdte = pubarr[0]
		ct = t[1].replace("''","'")
		# ID, TITLE, PUBLISHED, SOURCE, LOF
		
		lof = int(t[4])

		moreLink = ""
		
		#if lof > 40:
		#	moreLink = "4MORE: N3WZ [ART]: %s" % t[0]	
		
		#headline = "%s HEADLINE [%s] '%s', #%s %s" % ("@ALLCALL", pubdte, ct, t[3], moreLink)  
		
		#headline = headline.strip()
		
		headline = "%s HEADLINE [%s] '%s', #%s" % ("@ALLCALL", pubdte, ct, t[3]) 
		
		print(headline)
		
		while s.GetStationStatus() == "CLOSED":
			print("Waiting to send ..." + str(datetime.now()))
			time.sleep(2)
		s.SendToJS8(headline)
		while s.GetStationStatus() == "CLOSED":
			print("Waiting to send ..." + str(datetime.now()))
			time.sleep(2)
		time.sleep(bigSleep)

def TopStoriesFromAll():
	
	s = JS8Client()

	ti = GetTopHourly("INFOWARS")
	tn = GetTopHourly("NYT")
	tz = GetTopHourly("ZEROHEDGE")
	ty = GetTopHourly("YAHOO")
	tc = GetTopHourly("CNN")
	tb = GetTopHourly("BBC")
	
	tops = []
	
	tops.append(ti[0])
	tops.append(tz[0])
	tops.append(ty[0])
	tops.append(tc[0])
	tops.append(tn[0])
	tops.append(tb[0])

	for t in tops:
		pubarr = str(t[2]).split()	
		pubdte = pubarr[0]
		ct = t[1].replace("''","'")
		
		# ID, TITLE, PUBLISHED, SOURCE, LOF
		
		lof = int(t[4])

		moreLink = ""
		
		if lof > 40:
			moreLink = "4MORE: N3WZ [ART]: %s" % t[0]	
		
		headline = "%s HEADLINE [%s] '%s', #%s %s" % ("@ALLCALL", pubdte, ct, t[3], moreLink)  
		
		print(headline)
		while s.GetStationStatus() == "CLOSED":
			print("Waiting to send ..." + str(datetime.now()))
			time.sleep(2)
		s.SendToJS8(headline)
		while s.GetStationStatus() == "CLOSED":
			print("Waiting to send ..." + str(datetime.now()))
			time.sleep(2)
		time.sleep(bigSleep)

def TopStories(messageInfo):
	
	s = JS8Client()
	
	try:	
		#2S5: N3WZ  [TOP]: NYT, 1
		mp = messageInfo.split(':')
		
		if len(mp) < 3:
			return

		callsign = mp[0].strip()
		step1 = mp[2].strip()
		step2 = step1.split(',')
		rn = step2[1].strip().split()
		src = step2[0].strip()	
		numberOf = rn[0].strip()

		print("Handling %s request ..." % src)
		print(messageInfo)
		print("From: " + callsign)
		print("Top: " + numberOf)

		tops = GetTop(src, numberOf)
			
		for t in tops:
			pubarr = str(t[2]).split()	
			pubdte = pubarr[0]
			# ID, TITLE, PUBLISHED
			ct = t[1].replace("''","'")
			
			# ID, TITLE, PUBLISHED, SOURCE, LOF
			
			lof = int(t[4])

			moreLink = ""
			
			if lof > 40:
				moreLink = "4MORE: N3WZ [ART]: %s" % t[0]	
			
			headline = "%s HEADLINE [%s] '%s', #%s %s" % (callsign, pubdte, ct, t[3], moreLink)  
			
			print(headline)
			while s.GetStationStatus() == "CLOSED":
				print("Waiting to send ..." + str(datetime.now()))
				time.sleep(5)
			s.SendToJS8(headline)
			while s.GetStationStatus() == "CLOSED":
				print("Waiting to send ..." + str(datetime.now()))
				time.sleep(5)
			time.sleep(bigSleep)		

	except:	
		print("An exception occurred: getting top stories")
	
def handleArticle(messageInfo):
	
	try:
		#K7IAC: N3W5 [ART]: 237 ♢  
		
		s = JS8Client()
		
		mp = messageInfo.split(':')
		
		if len(mp) < 3:
			return
		
		callsign = mp[0].strip()
		
		step1 = mp[2].strip().split()

		number = step1[0].strip()

		print("Handling article request ...")
		print(messageInfo)
		print("From: " + callsign)
		print("Article: " + number)

		recd = GetArt(number)
		
		art = recd[0]
		src = recd[1]
		lnk = recd[2]
		
		if len(art) > 150:
		
			art2 = art.replace("\n", " ")
			art2 = art2.replace("''","'")
		
			print("bigger than 150 chars")
			
			if len(art2) > 500:
				art2 = art2[0:500]
			
			pts = math.ceil((len(art2)/150))
			buffr = ""
			part = 1
			for c in art2:
				buffr += c
				if len(buffr) == 150:
				
					artInfo = "%s ART_%s %s #%s (%s/%s)" % (callsign, number, buffr, src, str(part), str(pts))  
				
					print(artInfo)
					
					s.SendToJS8(artInfo)
					
					buffr = ""
					part += 1
					time.sleep(1)
					while s.GetStationStatus() == "CLOSED":
						print("NEWS SERVICE TIME: " + str(datetime.now()))
						time.sleep(1)
					time.sleep(60)
			
			if len(buffr) > 0:
				artInfo = "%s ART_%s %s #%s (%s/%s)" % (callsign, number, buffr, src, str(part), str(pts))  
				print(artInfo)
				s.SendToJS8(artInfo)
				buffr = ""
			time.sleep(bigSleep)

		else:		
			art2 = art.replace("\n", " ")
			art2 = art2.replace("''","'")
			# ARTICLE, SOURCE
			artInfo = "%s ART_%s %s ... (MORE @ %s)" % (callsign, number, art2, src)  
			print(artInfo)
			while s.GetStationStatus() == "CLOSED":
				print("Waiting to send ..." + str(datetime.now()))
				time.sleep(5)
			s.SendToJS8(artInfo)
			while s.GetStationStatus() == "CLOSED":
				print("Waiting to send ..." + str(datetime.now()))
				time.sleep(5)
			time.sleep(bigSleep)
	except:
		print("An exception has occurred: getting news article")

def NewsCycle(DirectedPath):
	
	prevDLineNo = 0

	newsl = "news_line.txt"

	if(exists(newsl)):
		tf = open(newsl, "r")
		tfs = tf.read().strip()
		if(tfs != ""):
			prevDLineNo = int(tfs)
		tf.close()

	readerf = open(DirectedPath)

	CALLSIGN = ""
		
	UTCDTM = ""
		
	MSGINFO = ""

	dirLine = 0
		
	uploaded = 0
		
	try:
		# Further file processing goes here
		for x in readerf:

			#0 UTC,1 FREQ,2 OFFSET,3 SNR, 4 MESSAGE

			recd = x.split('\t')

			UTCDTM = recd[0]
			
			OFFSET = recd[2]
			
			SNR = recd[3]
			
			FREQ = recd[1]
			
			MSG = recd[4]
										
			dirLine += 1
				
			if(dirLine > prevDLineNo):
			
				if "[ART]:" in MSG:
					handleArticle(MSG)

				if "[TOP]:" in MSG:
					TopStories(MSG)

				wf = open(newsl, "w")
				wf.write(str(dirLine))
				wf.close()
	
	finally:
		readerf.close()

def CycleFeeds():
	infowars = "https://www.infowars.com/rss.xml"
	zh = "https://feeds.feedburner.com/zerohedge/feed"
	yahoo = "https://news.yahoo.com/rss/"
	cnn = "http://rss.cnn.com/rss/cnn_topstories.rss"
	bbc = "http://feeds.bbci.co.uk/news/world/us_and_canada/rss.xml"
	nyt = "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml"
	onion = "https://www.theonion.com/rss"
	bb = "https://babylonbee.com/feed"
	print("Grabbing Babylon Bee ...")
	GrabRSS(bb, "BB")
	print("Grabbing ONION ...")
	GrabRSS(onion, "ONION")
	print("Grabbing INFOWARS ...")
	GrabRSS(infowars, "INFOWARS")
	print("Grabbing ZEROHEDGE ...")
	GrabRSS(zh, "ZEROHEDGE")
	print("Grabbing YAHOO ...")
	GrabRSS(yahoo, "YAHOO")
	print("Grabbing CNN ...")
	GrabRSS(cnn, "CNN")
	print("Grabbing BBC ...")
	GrabRSS(bbc, "BBC")
	print("Grabbing NYT ...")
	GrabRSS(nyt, "NYT")

# FEEDS:
# 1. INFOWARS: https://www.infowars.com/rss.xml
# 2. ZEROHEDGE: https://feeds.feedburner.com/zerohedge/feed
# 3. YAHOO: https://news.yahoo.com/rss/
# 4. CNN: http://rss.cnn.com/rss/cnn_topstories.rss

clearConsole()
time.sleep(2)
print("Starting NEWS Server .")
time.sleep(1)
clearConsole()
print("Starting NEWS Server ..")
time.sleep(1)
clearConsole()
print("Starting NEWS Server ...")
time.sleep(1)
clearConsole()
print("Starting NEWS Server ....")
time.sleep(1)
clearConsole()

CycleFeeds()

if newsMode == 1:
	TopStoriesFromAll()

if newsMode == 2:

	ptime = datetime.now()
	
	while True:
		ntime = datetime.now()

		print("NEWS SERVICE: " + str(ntime))

		time.sleep(1)
		clearConsole()
		NewsCycle(DPath)	
		clearConsole()

		tdiff = ntime - ptime

		if tdiff.seconds > (60 * 5):
			print("Grabbing RSS feed info ...")
			ptime = datetime.now()
			CycleFeeds()
	
if newsMode == 3:
	TopStoriesFrom(newsServiceM3, 4)
	

I’m beginning to think …

I’m beginning to think the approach I’ve been taking with JS8 call is a bridge too far – and that I would be better off learning to compile the code, and just create my own branch. Make the changes I want in C++ to include interop with websites that are accessible on some given network using standard REST calls. Also, allow it a scripted response model so that any given JS8Call app can act as a “radio service” taking messages, and replying. Also, add in flexible topology and multi-app running instances on the same computer. Who knows, add in a built in connector for MYSQL for data logging and event logging for outside of process coding and scripting by other consumers … so I don’t know if I can, I’m 53 and burnt out and believe the world could explode, figuratively, in a few months.

But is it the end of the world? – no, not by a long shot …

So maybe I try.

Will it be easy? – don’t know … I think

And here’s the other thing …

JS8Call, RIGHT NOW, AS IS would allow you to build an organic twitter style decentralized relationship with other people using CB radio and this network WORKS even if the WWW is down … is it good for secrets, as is? – no … is it good enough for the public square? – yes.

You could sell eggs, right now, using JS8Call on CB Radio – just need to expand the network, more users, bigger world.

And I would think a lot of real anarchists and libertarians would be into this …

CB RADIO – NO HAM LICENSE …

(and then we go from there)

And this is all in JS8CALL.COM right now.

With some work? – who the fuck knows what’s possible.

I feel like the world of shortwave radio, and CB, needs a revolution – and this could be the beginning.

RADENGINEERING.TECH

RAD-TERMINAL: HOW TO HAVE FREE OFF GRID INTERNET 4-LIFE!

Where: https://www.preppershowsusa.com/prepper-show/be-prepared-expo-2022/

When: 4/23/2022, 11 AM MST (Utah Time)

Room: Classroom B

What: Class/Presentation “RAD ENGINEERING: FIFL”

Presenters: Justin Land and Dan Sullivan

Outline:

  1. Introduction: How we got into this, the story of RAD ENGINEERING. WHAT IS THE RAD TERMINAL? (5 minutes)
  2. Hardware: a) radio, b) computer, c) linkages and wiring … history of the radio tech and how it’s being used. JS8 (20 minutes)
  3. Software: history of WWW, what happened to TECH in the 70’s … why couldn’t we hook up TRS-80 / C64 computers to a CB in 1983 … what are bulletin boards? – how is radio LIKE a bulletin board … encryption strategies … encoding … ARS: Amateur Radio Services … what is an ARS? – remote procedure calls over CB radio, hitting python-agent receivers, hooking into actions … >sendto: >email: >payment: … command tags … EDI for radio? – small compact messaging AND payment services using voice recognition (20 minutes)
  4. Q/A (15 minutes)

THE RAD MANIFESTO: radengineering.tech

MP3: https://planetarystatusreport.com/mp3/20220225_A_RAD_MANIFESTO.mp3

Donate: https://www.paypal.com/paypalme/doctorfreckles

"If it doesn't work, we don't give up, we try something else." - Dr. Freckles (or someone he ripped off that said the same thing)

I’ll get this out of the way – the ideas presented below are not SPECIAL or even original … I dunno … I don’t think I’m a dummy, but I’m certain many dummies don’t think they are … I don’t think I’m special, I’m just tired of the LEARNED HELPLESSNESS. I think we have a right to dream and do, as we have a right to breathe.

We support RIGHT-TO-REPAIR at RADENGINEERING.TECH, everything we design, we document, software or hardware, will be OPEN … we can’t control our suppliers … but we can foster NEW freedom friendly suppliers …

What you see below is not our companies vision in any complete or limited form … we reserve the right, as we succeed or fail, to add new dreams to our list.

Is it possible others are working on now or have solved the problems listed below? – I HOPE THEY HAVE … and if they have, they should consider the open source and right-to-repair philosophy … it isn’t communism, it is human understanding. You can’t enforce this philosophy, but that’s ok … there will always be assholes. We want to make money, but we also want to change the world.

… finally …

We reserve the right to fail and try again.

We reserve the right to dream.

Here is what we dream of doing:

  1. THE RAD TERMINAL: this will begin as a home-brew movement, but we have the goal of building a ruggedized all-in-one terminal, with antenna deployment pack and DC battery power, within 1 year – version ONE of the RAD TERMINAL … RT-1. This system will be designed with right-to-repair features, to include simple, swappable, modules for components that have high variability within radio or computer design. As of this writing, 2/25/22, we are still in home brew phase.
  2. We talked about RTR (right-to-repair) already in terms of all our component designs and documentation.
  3. Rad TRUCK: this will be a self-sufficient (as possible given power features) communications node that would be useful in connection with WiFi based MESH networks AND as a local internet hub for folks that want their own local game nets, email, etc … and they don’t need to be connected ANYWHERE else.
  4. Project RTR #1: Local source all non-cpu, non-ram electronic components.
  5. Project RTR #2: Design and build a 3D printing system for CPU and RAM.
  6. We want to do #1 and #2 simultaneously, and that leads to project FREEDOM.
  7. Project Freedom: a project to build a 100% local sourced (within a few hundred miles, up to 2,000 miles) computer that is capable of running LINUX. It would be 100% right-to-repair friendly, to include a PDF describing how YOU TOO can build a system for 3D printing CPUs … and as much useful knowledge as we can share.
  8. Project Freedom has a sister project: Project RADIO: to design and build a 100% local sourced right-to-repair friendly radio system. We want to optimize component layout to make some parts of the radio optimized, stationary on the board (still repairable), and other parts in RTR-friendly component boxes that fold out, from a cube or cube-like module, where anyone can work on those parts too … but, perhaps certain intrinsically different radio components can be placed in a swap module component box – and that would mean switching bands/frequencies/wavelengths, event to include WiFi, would be as simple as swapping out a plastic plug, with an easy pop button.
  9. Project Tesla: a remotely controlled drone for radio-repeater operations. This will allow the use of microwave technology for data exchange, at high altitudes, and this system LINKED to ground RAD TERMINAL devices for even higher rates of no-nonsense communication.
  10. Project Space Diver: this will be our first foray into aerospace and tourism/entertainment/travel. We will run a “you can jump from the edge of space” business, where we design a very safe “pod” that is lifted to 20 miles, and has a velocity reduction/control multi-stage parachute system. Plus, we want to design a reusable/rechargeable balloon system, for hydrogen at first … the dangers from combustion are vastly reduced as you go up in altitude. This will be a way for people to see the “curve”, and I think we can reach a price point of around $1000.00 per dive. Again – they will be in an aerodynamically sound pod, with a pressure suit on in case of decompression. We will have as many safeguards against accidental harm as is feasible – but we’re talking about 20 miles up … so it’s dangerous, no matter the pod.
  11. Project S’klider: this will be our second foray into aerospace. This will be a tourism/entertainment like “Space Diver”, but we’re hoping ordinary people will be able to buy them, here’s the concept: design a lightweight glider, for high altitudes, that can fold into a gondola for a blimp type hydrogen balloon system. At say, 15 miles up, the balloon deflates and is pulled back into the glider, and the glider can then proceed, folding out its wings, like a well designed glider for high/medium altitudes. The S’klider should be able to repeat this maneuver, even in mid air, but slowly filling the balloon back up with stored hydrogen. The idea: you could glide a LONG WAYS, especially if you have atmospheric thermal mapping hardware and software, with a well designed glider … perhaps thousands of miles with AI computer assistance for optimal thermal altitude gain.
  12. Project FAST: quantum radio … I think IBM has been sitting on this … it would be hyper-bandwidth powerful, hyper-de-centralized, hyper-liberating … the internet would be dead after this … pretty much everyone would use a quantum radio … and encryption? – that gets fun using synchronized noise for message embedding … or quantum steganography …. fun …
  13. Project View: a high altitude array of dirigible micro-observatories … astronomical in nature. We would like to take high resolution pictures by combining many smaller high altitude drones into one large array optical telescope. You could have these all around the globe. They could assist in the early detection of dangerous near earth objects.
  14. Project Vacuum: the design and construction of a vacuum ship using magnetic field engineering to create an inner structure of force, whereby creating mass-free structure that can encapsulate a vacuum. This kind of ship would be “lighter than air” but in a very powerful way and it could allow for single-stage-to-orbit rocket ships.
  15. Project Orbit: if Project Vacuum is successful, build a convertible vacuum ship dirigible system, with a gondola system designed like a lifting body glider, so that in case of vacuum envelope failure, the gondola itself could breakaway and the passengers could land safely. This ship would use a standard chemical rocket engine to achieve orbit, but would be lifted by its vacuum envelopes to an optimal altitude. The ship would be capable of maneuvering around the planet, at 20 miles, to find an optimal launch location for orbit.
  16. Project D.B. Cooper: a jacket/pant system that, if worn onto a plane, would allow a person to have a better chance of surviving a catastrophic failure of a passenger airliner. The system would be designed with carbon fiber and kevlar structuring to ensure protection against shrapnel, and an easy to deploy parachute system. For more money? – you get the 20 lb raft/radio combo … not sure about the sharks though.
  17. Project Mars: Orbit + synthetic gravity drive
  18. Project Stellar: Mars + focal synthetic gravity => space time cavitation => low density space time => mole drive, basically a mole drive using synthetic, projected, moments of synthetic gravity. This would reduce space time distance, the same way a mole, tunneling through the earth does it … little bits at a time … but the attraction principles would become nonlinear as speed increased, and this is an interesting area of research. Bottom line: worm holes work, but are very dangerous … this usese Einstein-Rosen Bridge concepts, but on a micro basis
  19. G-Ray: Build a gamma ray laser …
  20. We want to sponsor an expedition to Antarctica … Justin might not want to go, that’s ok, I might want him to man our base station repeater system as I read AT THE MOUNTAINS OF MADNESS … from fucking Antarctica … over shortwave radio with repeaters. But we also want to map the continent, and explore it.
  21. Freeze Ray: discover a useful and non-hazardous quantum endothermic particle that would cancel out the effects of photons
  22. New ZTuff: design a means of constructing useful synthetic matter from pure energy …
  23. OPEN PHP: if there isn’t an open php initiative, I want to start one … easy custom builds … transparent module viewing AND swapping for custom builds … and an ALL IN ONE deployable PHP friendly web server … other languages/APIs will work with it, but the most advanced, easy to control, PHP language and server will always be the best. We will also develop a simplified serialization and storage system that installs with the system, you can set how much memory you want it to use, both RAM and hard drive …
  24. Temperature tolerant cheap and durable super conductive material, with the same malleability features of copper.
  25. We want to foster the mentoring of young people in technology, sciences, math, so that our lives, though never perfect, can be far more kind and at peace and joy filled.

(we won’t be doing time travel – that’s crap)

JS8 Commands for API (TCP/IP)

Messages from JS8Call
CLOSE – JS8Call has been closed
INBOX.MESSAGES – A list of inbox messages
INBOX.MESSAGE – A single inbox message
MODE.SPEED – The current TX speed
PING – Keepalive from JS8Call
RIG.FREQ – The rig frequency has been changed
RIG.PTT – PTT has been toggled
RX.ACTIVITY – We received something
RX.BAND_ACTIVITY – The band activity window
RX.CALL_ACTIVITY – The call activity window
RX.CALL_SELECTED – The currently selected callsign
RX.DIRECTED – A complete message
RX.SPOT – A station we have heard
RX.TEXT – Contents of the QSO window
STATION.CALLSIGN – Callsign of the station
STATION.GRID – Grid locator of the station
STATION.INFO – QTH/info of the station
STATION.STATUS – Status of the station
TX.FRAME – Something we are sending
TX.TEXT – Text in the outgoing message window

Messages to JS8Call
INBOX.GET_MESSAGES – Get a list of inbox messages
INBOX.STORE_MESSAGE – Store a message in the inbox
MODE.GET_SPEED – Get the TX speed
MODE.SET_SPEED – Set the TX speed
RIG.GET_FREQ – Get the current dial freq and offset
RIG.SET_FREQ – Set the current dial freq and offset
RX.GET_BAND_ACTIVITY – Get the contents of the band activity window
RX.GET_CALL_ACTIVITY – Get the contents of the call activity window
RX.GET_CALL_SELECTED – Get the currently selected callsign
RX.GET_TEXT – Get the contents of the QSO qindow
STATION.GET_CALLSIGN – Get the station callsign
STATION.GET_GRID – Get the station grid
STATION.SET_GRID – Set the station grid
STATION.GET_INFO – Get the station QTH/info
STATION.SET_INFO – Set the station QTH/info
STATION.GET_STATUS – Get the station status
STATION.SET_STATUS – Set the station status
TX.SEND_MESSAGE – Send a message via JS8Call
TX.SET_TEXT – Sets the text in the outgoing message box, but does not send it.
WINDOW.RAISE – Focus the JS8Call window

The python example below is modified from the JS8 source code available here: http://js8call.com/

from __future__ import print_function

from socket import socket, AF_INET, SOCK_STREAM

import json
import time

#make sure you open port 2442 prior to opening JS8 application

#ubuntu command: sudo ufw allow 2442

server = ('127.0.0.1', 2442)

def from_message(content):
    try:
        return json.loads(content)
    except ValueError:
        return {}


def to_message(typ, value='', params=None):
    if params is None:
        params = {}
    return json.dumps({'type': typ, 'value': value, 'params': params})


class Client(object):
    first = True
    def process(self, message):
        typ = message.get('type', '')
        value = message.get('value', '')
        params = message.get('params', {})
        if not typ:
            return

        if typ in ('RX.ACTIVITY',):
            # skip
            return

        print('->', typ)

        if value:
            print('-> value', value)

        if params:
            print('-> params: ', params)


    def send(self, *args, **kwargs):
        params = kwargs.get('params', {})
        if '_ID' not in params:
            params['_ID'] = '{}'.format(int(time.time()*1000))
            kwargs['params'] = params
        message = to_message(*args, **kwargs)
        print('outgoing message:', message)
        self.sock.send((message + '\n').encode()) # remember to send the newline at the end :)
    
    def send2(self):
        message = "{'type': 'STATION.GET_STATUS', 'value': '', 'params': {'_ID': '1645105873058'}}"
        print('outgoing message:', message)
        self.sock.send((message + '\n').encode()) # remember to send the newline at the end :)
    
    def connect(self):
        print('connecting to', ':'.join(map(str, server)))
        self.sock = socket(AF_INET, SOCK_STREAM)
        self.sock.connect(server)
        self.connected = True
        try:
            # send a simple example query after connected

            self.send("TX.SET_TEXT", "WHAT IS GOING ON?")
			
            #list of commands here: 
            #https://planetarystatusreport.com/?p=646
            
            while self.connected:
                content = self.sock.recv(65500)
                if not content:
                    break
                print('incoming message')

                try:
                    message = json.loads(content)
                except ValueError:
                    message = {}

                if not message:
                    continue

                self.process(message)

        finally:
            self.sock.close()

    def close(self):
        self.connected = False

def main():
    s = Client()
    s.connect()

if __name__ == '__main__':
    main()

RT: RAD TERMINAL

MP3: https://planetarystatusreport.com/mp3/20220216_RAD_TERMINAL.mp3

Donate: https://www.paypal.com/paypalme/doctorfreckles

CONTACT US: PlanetaryStatusReport@gmail.com, DanielSullivan@planetarystatusreport.com

Guest: Justin L.

  1. How long have you been interested in radio?
  2. The world of Ham radio.
  3. What is JS8 and digital over radio?

Vision: to build an engineering company, specializing in radio and telecommunications, with a goal of creating an integrated and SECURE network that will allow information sharing, gaming, business, and secure communications, around the world and EVERYWHERE … cheaper than the WWW today … and owned by the people … truly decentralized.

If “crypto” wants to be truly independent and decentralized — then it needs to have the technological backbone to do so … it would need to be free of the WWW …

Elevator pitch …

I am working on a project with a friend in Utah. The project involves two basic parts:

  1. A no-logon bulletin board system, allowing users to post notes, read them, all in a GIS (geographical information systems) context.
  2. A digital citizen band and shortwave bidirectional radio bridge that allows an individual transceiver node and operator to integrate their system with our bulletin board system and vice versa. Our “white glove” offering will include effective encryption strategies for the messages themselves.

We are forming an engineering company if we are able, and this product/service combo will represent our first offering.

The product is called “notes”, but will:

  1. Allow journalists in difficult circumstances to file stories and reports – even when the local internet is shut down.
  2. Enable missionaries and activists overseas to coordinate and send/receive secure messages.
  3. Be a product that will excite young people about STEM and potentially be a great holiday gift.
  4. Be a way to dispatch and manage resources, globally.
  5. Integrate an EDI (electronic data interchange) system for formatted messaging between nodes.

Products:

  1. White-glove application capable of sending/receiving secure messages and integrating them into one web-based dashboard –
  2. Advertising space on free bulletin board.
  3. Rad-terminal: all in one radio/computer device, 3D printed brick/clam shell form factor, small enough to fit inside a backpack and containing all needed software and gear (to include antenna).
  4. Rad-brick: a small device that can interface your personal computer with a CB radio for digital text comms, among hobbyists, on 11 meters.
  5. Rad-truck: a vehicle which hosts a WiFi server and the broadcast equipment to provide emergency support, or special support for events, concerts … all integrated into the global PSR:NOTES system. A complete communications node for disaster scenarios: forest fire, earthquake, hurricane … etc.
  6. Rad-drone: a high altitude dirigible drone system for enhancing point-to-point shortwave and CB communications. A system that can be designed to provide area-wide WiFi and other services.

What do we want from you?

  1. Enthusiasm and involvement by home brew clubs in JS8 and similar technologies. Build out a network of technical knowledge and know how.
  2. Donors – want to support financially and be known as a founder AND have white-list access to the notes network.
  3. Investors … we need to raise 100K in the next 3 months to continue, and for this amount we will create a share structure for 10% ownership. This is a one time opportunity, the first investor to pool or have 100K can get a 10% stake …

We are just beginning on this journey, and this is connected to the podcast in a sense …

If you are interested in investing, please contact me: DanielSullivan@PlanetaryStatusReport.com