Things I have no choice but to write

Category: code

Coding HubSpot Utilities with Python

I’m cheap. And I use HubSpot. Those two occasionally conflict what I do to get around that is I use some of the developer features to create HubSpot utilities to do some simple data cleanup. Any sufficiently complex CRM will need this from time to time. I use mine for business and for politics.

I find the Associations object in HubSpot intellectually interesting, but inpractice, annoying. In my view, everything about a Contact object should be on the Contact record. So, what the intelligence function will do is often look at the email domain and create an Association. But it does this while leaving the company name on the Contact blank. I wanted a simple bulk way to fix this. And usually when I look at problems like this, I reach for Python. This time was no different.

Full Disclosure: I did use Google Gemini 3 Pro in Visual Studio Code to code this. I don’t think this was vibe code because I gave it enough specific instructions about how to code Python. I think the standard definition of vibecoding is someone who doesn’t know the technology, and I was telling Google Gemini how I like my “f” statements to appear, for example. If you think it’s vibe coding, drop a comment below.

HubSpot APIs

You have to be careful, because there are two separate models for building and coding around HubSpot. They have something which they call “legacy apps” which is essentially making rest API calls to pull data from various objects. The name legacy is a bit disturbing because it means it’ll go away. I’m not sure that’s a good thing.

They have a second model which they built around Projects, and uses Node.js. The principal purpose of this is to build extensions inside the UI and the HubSpot app itself. But it does give you a rather byzantine way of getting an API key, so that your applications are broken out by project. Intellectually, I like the project model, but as an operational metaphor, and its basic usage, I think it stinks. Too complicated. I’ll use it, but oy.

That said, here’s the code. If you want me to build you something, contact me here.

Build Your Own Geiger Counter with Raspberry PI

 The result of Covid and Work From Home has been….we stay home a lot. There are upsides, like not commuting every day. There are downsides, as we have more idle time. Since my memoir might be titled “A Mind Forever Wandering,” I was thinking one day about how much we really know about background radiation. This led to a couple of searches around Geiger Tubes, and real-time databases, etc.

After a few random purchases around the internet and a bit if python code and a left over Raspberry PI 4 1G box, I have put together a DIY Geiger Counter. Here is how I did it, and here is the code, etc, you’ll need.

Here’s what you need:

Set up Raspberry PI

First, get a Raspberry PI 3 or 4. You’ll need some kind of Raspbian OS/Raspberry PI OS on it. I always use the Raspberry PI OS installation instructions here. In short, get the OS and the imager, and create an image on the SD card. Then boot up the Raspberry PI.

You’ll also need to add Python3 and pip to get the code working. You’ll need to do something like:

$ sudo apt install python3 pip

I am using Python 3. I have not tested Python 2. Once done with that, you should use pip to install the following additional packages:

$ pip install influxdb_client RPi.GPIO

Set Up Geiger Tube

Next, Set up the Geiger-Miller tube, and the board. My pinout for a Raspberry Pi 4 1G device is pretty simple. GND pin on the board goes to pin 6. The 5V pin is wired to pin 2 for 5V of power, and the VIN input line is wired to pin 7, GPIO4. (No reason not to do pin 3 or 5. It’s just what I picked). I also pulled the J1 jumper, since the clicks get annoying. Back background radiation is about 15-35 CPM, BTW. Which is normal. About 0.11-0.15 microsieverts for those of you doing math in your heads.

Next, set up the code. My Raspberry Pi Geiger Counter code is here. You will have to set up your Influx DB v2 database, but I’ll write that up in the next blog entry.

Once you do connect to to InfluxDB you’ll be able to get cool graphs like this, in the InfluxDB v2 UI:

 

 

“CPM” here means clicks per minute. The full build is pictured below:

 

 

Questions? Ask them in the comments.

Like this post? Buy Me a Coffee….

Buy Me A Coffee

More links to Related Projects

 

 

 

 

WUnderground and Weather Station Integration with Python to Wavefront

(originally posted on VMware.com)

Here’s a quick post about the latest integrations with Wavefront. In the past, we’ve done Tesla and Nest integrations, but Durren Shen recently posted a blog about integrating Wavefront with an Ambient Weather weather station and WUnderground, the crowd sourced weather site. (The API info is here.)

Durren’s post is here. (Follow him here.) He also talked about code as well. I have cleaned it up and posted it to the GitHub repo here. To be clear, Durren (AKA durren ) wrote the code, I just cleaned it up.

The code is essentially this:

# Pulling data from WUnderground and sending to Wavefront by Python
#
# Core original code written by Durren Shen @durrenshen 
# in a blog at https://www.wavefront.com/weather-metrics/
# 
# Cleaned up by Bill Roth @BillRothVMware
#
import urllib2
import json
import logging
import socket
import sys
import time
import re
import syslog
sock = socket.socket()

#
# Below assumes the proxy is running on the same system. YMMV
#
sock.connect(('127.0.0.1', 2878))
#
# Set the source to yours.
#
sourceName = 'BrothPWS'
#
# Add your key here. You can get an API key here: https://www.wunderground.com/weather/api/

# Also change KCASANJO821.json to your station. Or you can use this one.
# 

f = urllib2.urlopen('http://api.wunderground.com/api/Y/conditions/q/pws:KCASANJO81.json')

json_string = f.read()

parsed_json = json.loads(json_string)

temp_f = parsed_json['current_observation']['temp_f']

sock.sendall('weather.temp_f ' + str(temp_f) + ' source=' + sourceName + ' \n')

humidity = parsed_json['current_observation']['relative_humidity']

sock.sendall('weather.humidity ' + re.sub("[^0-9]", "", str((humidity))) + ' source=' + sourceName + ' \n')

wind_degrees = parsed_json['current_observation']['wind_degrees']

sock.sendall('weather.wind_degrees ' + str(wind_degrees) + ' source=' + sourceName + ' \n')

wind_mph = parsed_json['current_observation']['wind_mph']

sock.sendall('weather.wind_mph ' + str(wind_mph) + ' source=' + sourceName + ' \n')

wind_gust_mph = parsed_json['current_observation']['wind_gust_mph']

sock.sendall('weather.wind_gust_mph ' + str(wind_gust_mph) + ' source=' + sourceName + ' \n')

pressure_in = parsed_json['current_observation']['pressure_in']

sock.sendall('weather.pressure_in ' + str(pressure_in) + ' source=' + sourceName + ' \n')

pressure_trend = parsed_json['current_observation']['pressure_trend']

sock.sendall('weather.pressure_trend ' + str(pressure_trend) + ' source=' + sourceName + ' \n')

dewpoint_f = parsed_json['current_observation']['dewpoint_f']

sock.sendall('weather.dewpoint_f ' + str(dewpoint_f) + ' source=' + sourceName + ' \n')

feelslike_f = parsed_json['current_observation']['feelslike_f']

sock.sendall('weather.feelslike_f ' + str(feelslike_f) + ' source=' + sourceName + ' \n')

visibility_mi = parsed_json['current_observation']['visibility_mi']

sock.sendall('weather.visibility_mi ' + str(visibility_mi) + ' source=' + sourceName + ' \n')

solarradiation = parsed_json['current_observation']['solarradiation']

sock.sendall('weather.solarradiation ' + str(solarradiation) + ' source=' + sourceName + ' \n')

UV = parsed_json['current_observation']['UV']

sock.sendall('weather.UV ' + str(UV) + ' source=' + sourceName + ' \n')

precip_1hr_in = parsed_json['current_observation']['precip_1hr_in']

sock.sendall('weather.precip_1hr_in ' + str(precip_1hr_in) + ' source=' + sourceName + ' \n')

precip_today_in = parsed_json['current_observation']['precip_today_in']

sock.sendall('weather.precip_today_in ' + str(precip_today_in) + ' source=' + sourceName + ' \n')

observation_epoch = parsed_json['current_observation']['observation_epoch']

syslog.syslog('Weather logged at ' + str(observation_epoch));

f.close()

sock.close()

It can produce a dashboard like this:

WeatherBlogCapture.PNG

This was for the old Wavefront, which is now Tanzu Observability. You can see the original post here.

© 2026 Bill Roth

Theme by Anders NorenUp ↑