This is a follow-up article on our previous article about controlling the LED strip via ESPHome with a relay.
What you're seeing above is about the simplest circuit you can build in order to control a "dumb" 24 volt DC LED strip.
For the smart Prusa enclosure project I'm working on, I've been looking at alternatives to control the two loads (fan and lighting) that will go in the Prusa MK4 enclosure. I believe I have finally settled on the final components we'll use to drive the loads; we are going to use a MOSFET module for the energy-demanding loads in our circuit — the fan and the LED strip.
A MOSFET (short for metal-oxide semiconductor field effect transistor) is a sort of "amplifier of logic gates". You feed its low-voltage inputs with a small voltage that crosses a specified threshold, and they immediately open up to let a much higher voltage through their outputs. You cut the power to the inputs, and they shut off the higher voltage path. The control voltage is usually logic level (3.3 volts or 5 volts, with the control current in the milliamp range) but the controlled voltage and current can be much, much higher.
Why use a MOSFET? MOSFETs are very efficient (almost as efficient as relays). MOSFETs, unlike relays, are quiet— they don't click when they toggle. MOSFETs are routinely used to build modules where the low-voltage side and the high-voltage side are completely isolated, which makes the low-voltage side safe from any high voltage (the MOSFET we will be using is of that kind). Finally, many MOSFETs can react to power on and off very quickly (up to a megahertz range), which means you can use them as controllers for dimming lights or variable speed fans; if you've heard the term PWM, you can guess that MOSFETs are often what's driven using PWM.
Initially, I had decided I would use the very popular IRF520 module, depicted here:
This module is extremely popular, it supports very high currents and voltages, it's very efficient, and it's incredibly cheap. Practically everyone with an Arduino has used this thing. The catch? The logic level needed to activate this MOSFET module is 5 volts; that voltage is not something I could supply from a GPIO pin of my ESP32 device. I tried it; it didn't work.
So I searched for equivalent modules, and I ended up finding the D4184 MOSFET control module:
It's a super simple device. It's cheap. It can activate with 3.3 volts DC, which means I can use it directly from the ESP32 device. It demands only 2 milliamps of power from GPIO pin through control loop to ground. It can drive the LEDs and the fan I need easily. It's very small. The low- and high-voltage sides are optoisolated. And it's plug–and-play — I barely need to add any component to get this to work! No bring-your-own-transistor, no bring-your-own-resistor — it's ready to go.
Regrettably, mine came with the screw-on terminals not yet mounted... but that's nothing a bit of solder and flux can't fix.
Since I will be reusing nearly all of the materials I used in the relay build, please refer to that post for details and suppliers of the parts.
Here's what you'll need for this build.
OK. Eager to find out the theory of operation? Let's first look at the wiring.
GND
on the module, and a GPIO output pin from your ESP32 to the PWM
terminal on the module.
GPIO27
.+
on the module to the positive terminal of a high voltage (up to 30 volts DC) source; once connected, connect your power source's negative terminal (the ground) to the -
pin on the module. This completes the high voltage supply to the MOSFET module.LOAD
pin on the module, and your load's positive to the high voltage supply's positive terminal.LOAD
MOSFET module pin.The complete circuit diagram is here (and also attached to this post as PDF):
Here is a close-up of the MOSFET module pinout — you can contrast the wire color coding with the picture of the full build at the top of this post:
This part assumes you have ESPHome installed and know how to use it. It's fairly easy once it's set up on your machine.
Here is a sample sketch. Create this as a new configuration in your ESPHome setup, then add the code below to the configuration (making sure to preserve the api
and ota
sections of the configuration you created). After doing so, flash it to your device via serial (your USB port) the first time. Subsequently, you can flash changes via Wi-Fi.
substitutions: name: mosfet-tester friendly_name: MOSFET tester esphome: name: ${name} friendly_name: ${friendly_name} name_add_mac_suffix: false esp32: # XTVTX ESP32 (wroom) board: nodemcu-32s framework: type: arduino # Enable logging logger: level: debug # Enable Web. # Turn me off and enable below. web_server: port: 80 include_internal: true local: true # Enable Home Assistant API # You'll use your own configuration's API section. # api: # encryption: # key: ">API encryption key<" # You'll use your own configuration's OTA section. # ota: # password: ">OTA password<" # The following will require you to have these two secrets # in your ESPHome secrets file. wifi: ssid: !secret wifi_ssid password: !secret wifi_password ap: ssid: ${friendly_name} password: password button: - platform: restart name: Restart entity_category: diagnostic icon: mdi:restart - platform: safe_mode name: Safe mode restart entity_category: diagnostic icon: mdi:restart-alert sensor: - platform: wifi_signal name: "Wi-Fi signal strength" update_interval: 10s entity_category: "diagnostic" - platform: internal_temperature name: "Device temperature" update_interval: 10s entity_category: "diagnostic" output: - platform: gpio # D27 on chip. pin: GPIO27 id: "out_1" light: - platform: binary name: Camera light id: camera_light output: out_1 icon: mdi:led-strip-variant
Assuming your Wi-Fi credentials were correct, then once the device is flashed, your device will appear in your local network with an IP address given by your router (assuming your home networking setup is like most everybody else's). ESPHome's log screen, which appears immediately after flashing the ESP32 device via USB, should give you the IP address to visit on your browser, but if you get nothing, try looking up the IP address of the device in your router's status or configuration pages.
If, after one minute, the device has yet to connect to Wi-Fi, then it will start up a captive portal you can access with your phone to input the Wi-Fi credentials for your wireless network. Use the captive portal to configure your wireless network into the ESP32 device, and try again.
Bonus exercise: can you turn the circuit into a dimmer? Yes, you can! In the output:
section of the sketch, turn platform: gpio
into platform: ledc
. Then, in the light:
section, change platform: binary
to platform: monochromatic
. Reflash your ESP32 device — you can now control the intensity of the LED strip with a slider!
With the IP address of your ESP32 opened up in your browser at http://<the IP address>/
, try flicking the light on and off:
Now let's see how the build works. The circuit is not that dissimilar from our relay build, but let's go over a very simplified explanation of what's going on anyway:
LOAD
and and +
of the MOSFET module.If you have to TL;DR this sequence of operation, the MOSFET acts much like a relay would. There's an important distinction: unlike in the case of a relay-switched circuit, the low-voltage side sees no inductive reactance when the MOSFET shuts off. When we use the MOSFET, the concern about inductance exists on the high-voltage side.
Sure! This circuit is now ready to be added to Home Assistant:
I recently had the need to redirect a Python program's output to the system journal. But not just that program's — all its subprocesses too. None of the tricks involving redirect_stdout()
work for that set of requirements. Fortunately, there is a very easy way to do exactly this. Here's what you need to put at the very top of your Python program:
#!/usr/bin/python3
import os, subprocess, sys
# Close all stdio except stdin.
os.close(1)
os.close(2)
# Spawn the program we want to log to. This program must read our output
# via stdin. Spawn the program with its stdin as a pipe to that effect.
# In this example, we're using the standard logger utility that logs
# all its input to the journal or to syslog, but this could very well be
# a program that outputs to a network, or to a file, or something else.
logger = subprocess.Popen(["logger", "-t", "my-logged-program"], stdin=subprocess.PIPE)
# By the magic of POSIX stdio, that pipe just got assigned file descriptor
# number 1. This means our program now has standard output connected to
# the logger process above. But standard error is still closed, so we
# will fix that right in this very line.
os.dup(logger.stdin.fileno())
# Now we have stdout and stderr. Exercise them! print("Stdout") print("Stderr", file=sys.stderr)
# You should see no output on the console. However, that output should
# still appear on your journal or syslog.
With this trick, stuff like sys.stdout.write()
will work as well. And, most importantly, any subprocesses started by your Python program will inherit the stdio of your Python program now — so long as the subprocess handling our stdio is still running, it will receive all child processes' output in its standard input.
Needless to say, the trick above only works on POSIX systems. It will not work on Windows.
Earlier today, I was attempting to set up the a polkit (formerly PolicyKit) policy on a system of mine, which I use as a media center and therefore I must be able to control remotely. Part of the work I was doing used polkit.log()
to dump some policy information to the system log; polkit is supposed to print to the log whenever polkit.log()
is used, but this wasn't working.
Here's the policy in question:
/* Allow Home Assistant to shut down, lock, suspend or log anyone off the system without authentication. */
polkit.addRule(function(action, subject) {
if (subject.user == "assistantsh") {
polkit.log("Subject " + subject + " attempting action " + action);
if (
action.id == "org.freedesktop.login1.power-off"
||
action.id == "org.freedesktop.login1.power-off-multiple-sessions"
) {
polkit.log("Forced power off permitted for subject" + subject);
return polkit.Result.YES;
}
if (
action.id == "org.freedesktop.login1.suspend"
||
action.id == "org.freedesktop.login1.suspend-multiple-sessions"
) {
polkit.log("Suspend permitted for subject" + subject);
return polkit.Result.YES;
}
if (
action.id == "org.freedesktop.login1.manage"
||
action.id == "org.freedesktop.login1.manage-multiple-sessions"
) {
polkit.log("Manage sessions permitted for subject" + subject);
return polkit.Result.YES;
}
if (
action.id == "org.freedesktop.login1.lock-sessions"
) {
polkit.log("Lock sessions sessions permitted for subject" + subject);
return polkit.Result.YES;
}
}
});
I was having trouble getting it to work, and the polkit.log()
stanzas were not producing anything in the journalctl -f
journal (as they should, because it's documented behavior).
Curious, I looked into /usr/lib/systemd/system/polkit.service
and I found the following:
[Service]
...
ExecStart=/usr/lib/polkit-1/polkitd --no-debug
...
Whaaat! By default, polkit.log()
is suppressed on Fedora, because of that flag!
The fix was easy. I removed the --no-debug
from the configuration file, and issued systemctl daemon-reload ; service polkit restart
on the console.
Bam! My polkit.log()
messages began showing up on the console.
Sure, the removed flag will reappear on that file next time polkit is updated, but I don't care about that — I only needed to see the messages today.
For anyone who wants to know, here is the shell program that specific system uses to let a remote system manage various aspects of it via SSH using polkit policies instead of sudoers
root access. The program below is set as a shell of the local user designated for remote management.
#!/usr/bin/python3 import os, shlex, subprocess, sys testing = False os.close(1) os.close(2) logger = subprocess.Popen(["logger", "-t", "assistantsh"], stdin=subprocess.PIPE) os.dup(logger.stdin.fileno()) logger.stdin.close() def report(msg, *args): if args: msg = msg %args print(msg) if not sys.argv[1:] or sys.argv[1] != "-c": report("rejected command line %s", sys.argv[1:]) sys.exit(8) args = sys.argv[2:] if args == ["poweroff"]: report("powering off") if testing: sys.exit(0) {% if is_vm %} os.execv( "/usr/bin/qrexec-client-vm", [ "/usr/bin/qrexec-client-vm", "dom0", "admin.dom0.Poweroff", ] ) {% else %} ret = subprocess.run( [ "/usr/bin/systemctl", "poweroff", "-i", "--no-ask-password", ], capture_output=True, text=True, check=False, ) if ret.returncode: report(f"failed to power off ({ret.returncode}): {ret.stderr}") else: report("successfully powered off") sys.exit(ret.returncode) {% endif %} elif args == ["loginctl lock-sessions"]: report("evicting and locking sessions") {% if is_vm %} if testing: sys.exit(0) os.execv( "/usr/bin/qrexec-client-vm", [ "/usr/bin/qrexec-client-vm", "dom0", "admin.dom0.Lock", ] ) {% else %} ret = subprocess.run( [ "/usr/bin/loginctl", "terminate-seat", "seat0", "--no-ask-password", ], capture_output=True, text=True, check=False, ) if ret.returncode: report(f"failed to lock sessions ({ret.returncode}): {ret.stderr}") sys.exit(ret.returncode) else: report("successfully evicted sessions") ret = subprocess.run( [ "/usr/bin/loginctl", "lock-sessions", "--no-ask-password", ], capture_output=True, text=True, check=False, ) if ret.returncode: report(f"failed to lock sessions ({ret.returncode}): {ret.stderr}") else: report("successfully locked sessions") sys.exit(ret.returncode) {% endif %} elif args == ["systemctl suspend"]: report("suspending system") {% if is_vm %} if testing: sys.exit(0) os.execv( "/usr/bin/qrexec-client-vm", [ "/usr/bin/qrexec-client-vm", "dom0", "admin.dom0.Suspend", ] ) {% else %} ret = subprocess.run( [ "/usr/bin/systemctl", "suspend", "--no-ask-password", "-i", ], capture_output=True, text=True, check=False, ) if ret.returncode: report(f"failed to suspend system ({ret.returncode}): {ret.stderr}") else: report("successfully suspended system") sys.exit(ret.returncode) {% endif %} report("rejected command %s" % args) sys.exit(16)
This shell program is invoked (via passwordless SSH, using an SSH key for authentication) by Home Assistant on the remote system. Here's a relevant snippet of the Home Assistant configuration that will call upon this program on the machine to be managed (in this sample it's called roxanne
):
# Provide the necessary commands to run actions on the machine.
shell_command:
lock_roxanne: /usr/bin/ssh -o "BatchMode yes" -o "ConnectTimeout 30" assistantsh@roxanne loginctl lock-sessions
suspend_roxanne: /usr/bin/ssh -o "BatchMode yes" -o "ConnectTimeout 30" assistantsh@roxanne systemctl suspend
turn_off_roxanne: /usr/bin/ssh -o "BatchMode yes" -o "ConnectTimeout 30" assistantsh@roxanne poweroff
# Quality of life enhancement: buttons to suspend and lock / log out.
template:
- button:
- name: Suspend roxanne
press:
service: shell_command.suspend_roxanne
unique_id: suspend_roxanne
- name: Lock roxanne
press:
service: shell_command.lock_roxanne
unique_id: lock_roxanne
# Standard Wake-on-LAN switch with a command to turn off the machine.
switch:
- platform: wake_on_lan
mac: th-em-ac-ad-dr-es
broadcast_address: th.eip.add.res
name: roxanne
host: roxanne
turn_off: {
"service": "shell_command.turn_off_roxanne"
}
And that is all.
Under the old X11 regime, a bit of xdotool windowactivate
magic used to do the trick when it came to raised windows.
Not so in Wayland anymore. Sadly, Wayland has no protocol that user-space applications can lean on to raise a window.
However, if your desktop session uses KWin (e.g. under a KDE Plasma session), this is certainly possible. Not only is it possible, it will work equally well whether your session is running under X11 or Wayland!
The following code is a Python script you should place under /usr/local/bin/kwin_wmgmt_helper
and make executable. Ensure you have both Python and the pydbus
library installed on your system as well. How the program works, and how to use the program is explained below.
#!/usr/bin/python3
import hashlib
import os
import pydbus
import subprocess
import sys
from gi.repository import GLib
def generate_dump_script():
return """
function kwindump() {
var clients = workspace.clientList();
for (var i=0; i<clients.length; i++) {
var client = clients[i];
console.warn("Client: " + client + "\\n Title: " + client.caption + "\\n Class: " + client.resourceClass);
}
}
kwindump();
"""
def generate_script(window_title, window_class):
window_title_escaped = (window_title or "").replace("'", "\\'")
window_class_escaped = (window_class or "").replace("'", "\\'")
return """
function kwinactivateclient(clientClass, clientCaption) {
var clients = workspace.clientList();
var compareToCaption = new RegExp(clientCaption || '', 'i');
var compareToClass = clientClass;
var isCompareToClass = clientClass.length > 0
for (var i=0; i<clients.length; i++) {
var client = clients[i];
console.log(client);
var classCompare = (isCompareToClass && client.resourceClass == compareToClass)
var captionCompare = (!isCompareToClass && compareToCaption.exec(client.caption))
if (classCompare || captionCompare) {
if (workspace.activeClient != client) {
workspace.activeClient = client;
}
callDBus(
'com.rudd_o.WindowManagement', '/com/rudd_o/WindowManagement', 'com.rudd_o.WindowManagement', 'WindowFound'
);
return;
}
}
callDBus(
'com.rudd_o.WindowManagement', '/com/rudd_o/WindowManagement', 'com.rudd_o.WindowManagement', 'WindowNotFound'
);
}
kwinactivateclient('%(window_class_escaped)s', '%(window_title_escaped)s');
""" % locals()
class WindowManagement(object):
"""
<node>
<interface name='com.rudd_o.WindowManagement'>
<method name='WindowFound'>
</method>
<method name='WindowNotFound'>
</method>
</interface>
</node>
"""
def WindowFound(self):
self.found = True
print(f"{sys.argv[0]}: window found", file=sys.stderr)
def WindowNotFound(self):
self.found = False
print(f"{sys.argv[0]}: window not found", file=sys.stderr)
def __init__(self):
self.found = None
def loadScript(path: str, name: str) -> int:
return int(
subprocess.check_output(
[
"dbus-send",
"--session",
"--dest=org.kde.KWin",
"--print-reply=literal",
"/Scripting",
"org.kde.kwin.Scripting.loadScript",
f"string:{path}",
f"string:{name}",
],
text=True,
).split()[-1]
)
def run_script_in_kwin(bus, path, name):
scripting = bus.get("org.kde.KWin", "/Scripting")["org.kde.kwin.Scripting"]
script_id = loadScript(path, name)
if script_id == -1:
unload = scripting.unloadScript(name)
assert unload, unload
script_id = loadScript(path, name)
script = bus.get("org.kde.KWin", f"/{script_id}")["org.kde.kwin.Script"]
script.run()
script.stop()
unload = scripting.unloadScript(name)
def execute(bus, window_title, window_class, quitter):
script_folder_root = os.getenv("XDG_CONFIG_HOME", os.environ["HOME"])
script_folder = os.path.join(script_folder_root, ".wwscripts")
name = hashlib.md5(f"{window_title}-{window_class}".encode("utf-8")).hexdigest()
path = os.path.join(script_folder, name)
script = generate_script(window_title, window_class)
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(script)
try:
run_script_in_kwin(bus, path, name)
except Exception as e:
print(f"{sys.argv[0]}: fatal error: {e}", file=sys.stderr)
sys.exit(4)
GLib.idle_add(quitter)
def dump(bus):
script_folder_root = os.getenv("XDG_CONFIG_HOME", os.environ["HOME"])
script_folder = os.path.join(script_folder_root, ".wwscripts")
name = hashlib.md5(f"{sys.argv[0]}-dump".encode("utf-8")).hexdigest()
path = os.path.join(script_folder, name)
script = generate_dump_script()
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(script)
try:
run_script_in_kwin(bus, path, name)
except Exception as e:
print(f"{sys.argv[0]}: fatal error: {e}", file=sys.stderr)
sys.exit(4)
def usage():
print(
"usage:\n\n"
f" {sys.argv[0]} <window title regexp> [optional command and args if not found]\n"
f" {sys.argv[0]} --class <window class> [optional command and args if not found]\n"
f" {sys.argv[0]} --dump\n"
"\n"
"Returns 1 when the window is not found, 0 when it is.\n"
"\n"
"If an optional command (with or without arguments) is specified"
" then the command will be run if the window is not found.\n"
"\n"
"--dump makes KWin dump to the journal a list of clients with their"
" window titles and resource classes. You can retrieve this list by"
" running journalctl _COMM=kwin_wayland under Wayland.",
file=sys.stderr,
)
sys.exit(os.EX_USAGE)
args = sys.argv[1:]
try:
window_class: str | None = None
window_title: str | None = args[0]
args = args[1:]
except IndexError:
usage()
if window_title == "--help":
usage()
if window_title == "--dump":
dump(pydbus.SessionBus())
sys.exit(0)
if window_title == "--class":
try:
window_title, window_class, args = None, args[0], args[1:]
except IndexError:
print(
f"{sys.argv[0]}: error: the --class parameter requires a window class",
file=sys.stderr,
)
usage()
optional_cmd = args
bus = pydbus.SessionBus()
wm = WindowManagement()
bus.publish("com.rudd_o.WindowManagement", wm)
loop = GLib.MainLoop()
GLib.idle_add(execute, bus, window_title, window_class, loop.quit)
loop.run()
if not optional_cmd:
sys.exit(0 if wm.found else 1)
os.execvp(optional_cmd[0], optional_cmd)
The small program above does the following, when you invoke it as such: kwin_wmgmt_helper Kodi
Kodi
(specifically, searching that regular expression in the window title of all running applications).0
) status if the window was found, or failure (1
) if the window was not found.This makes the program extremely useful for scripting desktop automation scenarios. I myself use it in Kodi — with my XDG desktop menu add-on for Kodi — to bring up specific applications that are already running on my desktop, instead of launching them. If I open Chromium, after all, I don't want to open another window of Chromium — I want to raise the window that's already open.
Other ways you can invoke the program as:
kwin_wmgmt_helper --class google-chrome
google-chrome
, and raises it.kwin_wmgmt_helper Konsole konsole
konsole
command instead.kwin_wmgmt_helper --dump
makes KWin dump a list of open window names and classes to the system journal. You can look at it using journalctl
(peruse the last few dozen lines).For the smart Prusa enclosure project I'm working on, I've been looking at alternatives to control the two loads (fan and lighting) that will go in the Prusa MK4 enclosure.
One of the alternatives is to use a relay to drive the LEDs and fan, all controlled by an ESP32 device. I didn't want to use a relay, and I still don't (I will likely end up using a MOSFET module, since MOSFETs are silent, and relays are not). That said, I still had to try the relay option, just to learn how it works.
You use relays when you need on/off control of a high voltage or current, driven by a low voltage low current device (like an ESP32). The way a relay works is, it has an internal coil that moves a switch from "off" to "on" (connecting common pin COM
to normally-open pin NO
) when the coil is energized across its two pins C1
and C2
by the specified voltage, producing a satisfying click when this action happens. When the voltage across the coil is not there, some relays (of the SPDT — single pole dual throw — type) bridge COM
to normally-closed NC
.
This project will be built on ESPHome, and is therefore natively compatible with Home Assistant. In other words, the ESPHome sketch you will program on your ESP32 device should be immediately addable to your Home Assistant instance — you can control your LED strip directly from your Home Assistant dashboard.
I originally bought some relay modules (which come ready-to-be-plugged into an ESP32 device), but the weirdos who sold me the modules at AliExpress did not send me modules — they just sent me bare relays. So I had to make myself, with low-level components, the equivalent switching network to a relay module. I have laid out in detail why each component is necessary.
Here's the bare minimum you'll need to get you started.
Here's the circuit schematic you'll have to hook up — it's explained in detail below, and attached to the bottom of this post as PDF as well.
In an electrical circuit schematic, green dots in crossing lines mean these lines are connected — when there is no dot in a crossing, those lines are not connected.
First, the basics:
3V3
pin on the ESP32. Connect the ESP32 GND
pin to negative out (this is also ground).Be careful! Do not mistake the input for the output — you'll fry the converter (ask me how I learned this!) Remember: the converter input takes 24 volts, and the output produces 3.3 volts. The input goes to the supply, the output goes to the ESP32 voltage pin.
Now, the switching network. This network runs exclusively at 3.3 volts; the circuit for switching is composed of the resistor, the transistor, the Schottky diode and the relay module. The general way it works is:
Here's how you wire this up:
C1
on the relay.C2
to:
3V3
pin.Here is an annotated close-up of the transistor and the Schottky diode, and how they should be wired up:
And here is an annotated picture of the relay (upside down, on its belly):
That completes the switching network.
Finally, the load network. This one runs at 24 volts:
COM
pin on the relay to the ground of your circuit.NO
(normally open) pin on the relay to the negative wire of your LED strip.
That's it!
This part assumes you have ESPHome installed and know how to use it. It's fairly easy once it's set up on your machine.
Here is a sample sketch. Create this as a new configuration in your ESPHome setup, then add the code below to the configuration (making sure to preserve the api
and ota
sections of the configuration you created). After doing so, flash it to your device via serial (your USB port) the first time. Subsequently, you can flash changes via Wi-Fi.
substitutions:
name: relay-tester
friendly_name: Relay tester
esphome:
name: ${name}
friendly_name: ${friendly_name}
esp32:
# XTVTX ESP32 (wroom)
# You may have to change this if the ESP32 device
# you bought is a of different type.
board: nodemcu-32s
framework:
type: arduino
# Enable logging
logger:
level: debug
# Enable anonymous Web control.
web_server:
port: 80
include_internal: true
local: true
# Enable Home Assistant API
# You'll use your own configuration's API section.
# api:
# encryption:
# key: "<api encryption key>"
# You'll use your own configuration's OTA section.
# ota:
# password: "<OTA password>"
# The following will require you to have these two secrets
# in your ESPHome secrets file.
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: ${friendly_name}
password: password
button:
- platform: restart
name: Restart
entity_category: diagnostic
icon: mdi:restart
- platform: safe_mode
name: Safe mode restart
entity_category: diagnostic
icon: mdi:restart-alert
sensor:
- platform: wifi_signal
name: "Wi-Fi signal strength"
update_interval: 10s
entity_category: "diagnostic"
- platform: internal_temperature
name: "Device temperature"
update_interval: 10s
entity_category: "diagnostic"
output:
- platform: gpio
pin: GPIO27
id: "out_1"
light:
- platform: binary
name: Camera light
id: camera_light
output: out_1
icon: mdi:led-strip-variant
Assuming your Wi-Fi credentials were correct, then once the device is flashed, your device will appear in your local network with an IP address given by your router (assuming your home networking setup is like most everybody else's). ESPHome's log screen, which appears immediately after flashing the ESP32 device via USB, should give you the IP address to visit on your browser, but if you get nothing, try looking up the IP address of the device in your router's status or configuration pages.
If, after one minute, the device has yet to connect to Wi-Fi, then it will start up a captive portal you can access with your phone to input the Wi-Fi credentials for your wireless network. Use the captive portal to configure your wireless network into the ESP32 device, and try again.
Once you have the IP address of your ESP32 device, visit the Web site http://<the IP address>/
. This is how the whole thing will look like in action:
The sample you see on video has some differences from what you'll get in the sample sketch. For example, you'll get Camera light, but you won't get Camera light switch, since the sketch I pasted above is simplified to just control the LED strip.
So what's going on here?
And that concludes our adventure!
This post is a mirror from a short writeup by science fiction author Devon Eriksen.
Classical liberal societies are hackable because they tend to set higher and higher values on human life and safety over time.
Eventually, society reaches a state where the worst non-violent thing is held to be less bad than the mildest sort of violence necessary to stop that that thing.
It then becomes effectively illegal to stop anyone from doing that thing. In this social state of affairs, a grifter can victimize people in any way he chooses so long as he:
Shoplifters can stop employing stealth altogether and simply loot stores, knowing that they cannot be caught or punish, because store owners will be punished more severely for dishing out a beating, or simply restraining them for the police, than the punishment for theft.
Youtube "pranksters" can harass and threaten innocent people, knowing that standing six inches from someone and screaming in their face, or yelling to bystanders that some innocent person is a child rapist, will be punished less severely, if at all, than the beatdown / pepper spraying that this behavior invites.
Self-styled protestors can block the arteries of civilization, knowing that driving a car over them, which is the only response available to drivers, will be punished as murder, while they themselves would be unlucky to be charged with an infraction.
These are all people who have learned to hack classical liberalism, and I'm sure you can think of more examples.
So what is to be done?
First, the inhabitants of classical liberal society must realize that property is freedom.
If we cannot protect that which we build and invest in, that means we are not free, because our choices, our self-determination, and even little pieces of our lives, are being taken away from us by those who can deprive us of our property at will.
This means that we must mentally free ourselves from the attitude that violence is unacceptable. Instead, when confronted with a property crime, or an assault on our dignity or liberty, we must normalize the use of the minimum amount of force that will reliably and safely stop it.
Note that I say "normalize", not "legalize".
Legalizing is an act of the government, and in states where the government is willing to do this, this sort of thing isn't a widespread problem. No one is blocking roads in Tennessee, Idaho, or Montana, because they know the consequences would be swift and unpleasant.
In California, Chicago, Oregon, western Washington, and so on, the state will not put a stop to these things, because it wants them to happen.
So those of you who are forced to live in those states, and are unable to leave, must normalize beatdowns.
Yes, your state and local governments will want to punish you for playing rough with their beloved criminal underclass, and their precious insane hobos and bums.
But you must realize what the criminals and bums realized long ago... the police and the state are not ubiquitous, and their power to catch and punish you is much more limited than you think.
Yes, they will go after you much harder than they go after thugs, bums, and commies, because thugs, bums, and commies are their constituents and you are not.
But that's what "normalize" means. It means make normal. You all have to start doing it, or at least a lot of you. Because one or two people can be made an example of, but normal behavior cannot.
How long would this continue if every group of roadblocking communist agitators were beaten by a mob of angry motorists who carry a pair of thick socks and a set of Chinese mediation balls, or a bar of soap, in their cars?
You have to take your states back. Your governments will not do it for you. This whole thing was their idea. You have to realize they are the enemy, stop petitioning them to protect you, and start protecting yourselves.
Note to the reader: this project is as of now still unfinished and awaiting new parts. Do not attempt to replicate what is shown here yet. This warning will be removed once the instructions are complete.
I recently acquired a very nice Original Prusa MK4 with its enclosure (which was quite the labor to put together!).
Prusa MK4 printers are fully compatible with Home Assistant — they have their own built-in integration that allows limited control of prints, and lets the user see the status + a preview of the printout. On that basis, I've already made a dashboard for myself, so I can monitor printing time and state.
Since I'll be printing filaments that emit styrene and other noxious gases, in addition to the enclosure I also ordered the advanced filtration system (and its requisite base board + power supply). The base board and supply can also power and control an LED strip (24 volts), and the board includes a two-push-button front panel to turn the light and the fan on and off (not depicted here).
While my LED strip is still not here, I could still have put all of this together, and be ready to print noxious filaments. However, as you can see, I haven't yet put together the advanced filtration system. Why?
To me, it means:
The technical parts can be done with an ESPHome-programmed ESP32 device. The aesthetic and functional parts can be done with a little care.
This post explores doing exactly that.
You may want to read my series of guides on powering various electric devices using ESPHome and cheap electronics. This is background knowledge that will help you understand the details of the electronics we'll be building in this post:
Many of the components mentioned in those guides will be featured in this guide.
I need a circuit that does all of the above. For that circuit to become real, there are a few items I need to add to my shopping list:
First, I'll need an ESP32. ESP32s are microcontrollers from Espressif that (1) are very cheap (2) are very versatile (3) consume very little power (4) feature a lot of options for input and output, from GPIO through Bluetooth to Wi-Fi.
FIXME: put final device here (after testing ESP CAM cameras) and insert picture.
I'll need two MOSFET modules. This blog carries a fairly cool tutorial on how to use MOSFET modules — you should read it. These modules are needed because both the filtration fan and the LED strip require 24 volts and over 50 watts of power together (supplied by the power adapter Prusa ships), but the ESP32 device "speaks in 3.3 volts" and can only safely do 20 milliwatts per GPIO pin (before giving up the magic smoke). I bought my MOSFET modules from here:
I'll also need a MP1584EN / LM2596 step-down DC-DC converter, to take the 24 volts of the power supply and convert them into 3.3 volts that the ESP32 device needs. The photos below show how the board looks like almost exactly, but it may arrive with a chip that says 150
instead of 100
— this is fine.
I will need several perfboards (perforated boards). I won't be printing the circuit out on a PCB or use surface-mount components either, but I can't put a breadboard in the enclosure and expect that to be reliable or aesthetic — therefore, we'll be using perfboards for this project. I'll mount the relays, the ESP32 device,the power converters, pin headers and other needed components onto the perfboards. Get two 2.54mm pitch perfboards 50x70mm in size. For reference, this is how perfboards look like:
The enclosure needs lighting. To that effect, I bought a 5 meter LED strip that works with 24 volts DC. This will work perfectly with the power supply sent by Prusa Research. I will not be using the entire roll! Rather, I'll cut as much of the power strip I think it's necessary to illuminate the enclosure well for the camera to work at night, and then strategically place the segments (interconnected in series) on the roof of the enclosure to illuminate the printout. For the record, at 24 volts supplied, the roll consumes about 2 amperes — just this load alone would overwhelm the power supply that came with the base board. Never power the strip while on its roll for more than a few seconds at a time — you can overheat and burn it that way.
Some wiring will be necessary as well. To wit:
Get some insulated two-lead 22AWG wire to bring power to the LED strip. One of the sides will crimp into a LED strip connection module — the other side will screw into the high-voltage MOSFET headers (shown in blue on the photo above). Small segments of wire can be used to wire LED segments together after cutting them to size.
To wire the LED segments together after they've been cut to size, you'll need these solderless LED strip connection modules. The strip I will use is 10mm wide so get the 2-pin 10mm units. To make your life a little easier, you can choose to get both strip to wire as well as the strip to strip modules — but anything that lets you crimp a two-lead wire to the LED strip is fine.
Get JST XH 2.50mm pitch male cables and through-hole female headers; these will be used to hook up the front panel and the fan. In truth, you can choose to solve this interconnect issue in the way you prefer the most — all that's needed is enough four-wire conductor, and a way to attach two of these conductors to the circuitry. Here is what I did to solve this issue for myself: apart from the 22AWG wire I got, I also bought this header / connector / pin JST crimp kit and the JST header crimping tool. With these supplies, I can (a) provide stable connection points on the circuit boards, (b) make a 4-wire cable for the front panel of the exact length I need, and (c) replace the connector that ships with the fan cable with a JST connector.
I will need a female barrel socket to take up the 24 volts produced by the power supply. It's a 5mm barrel socket you can buy here, and this is how it looks like (both male and female depicted):
I will need a fuse holder and a 2 amp fuse. The fuse holder can be obtained here (it's depicted below) and the fuses can be these (but it's on you to check that they really do blow at 2 amps). The fuse is important for safety.
From Prusa Research, you'll need the PSU, the base board, and the advanced filtration system. I don't include photos here, because these are better photographed on Prusa Research's site (see the links).
I recommend you own a multimeter with alligator clips, and some DuPont wires or 2.54 mm header pins. These will be extremely useful to test for voltages and continuity. Without a multimeter, you are generally flying blind. Cables with retractable hooks on both ends will also be very useful for testing.
You will need a soldering iron and a roll of rosin core solder.
Finally, on the software side, we'll use ESPHome. ESPHome is software that makes it extremely easy to program these ESP32 devices; instead of having to hand-roll C++, all I have to do is put together a YAML file (which I'll supply below) and this puts together all the functionality we need from the circuit, almost straight into the ESP chip. You should install the ESPHome add-on on your Home Assistant instance; however, if you don't have Home Assistant and don't plan to use it, you can manually install ESPHome on your computer.
We'll use the base board as a mechanism to control fan and lighting manually. For that, we need to hook up those buttons to our ESP32 device; this is the first step to accomplishing that.
Carefully solder the top and bottom pins of each button to a two-lead wire each, then crimp pins to the other side of the wires, and insert those pins into a male JST plug as explained below; the crimped pins should click into place as they are inserted. The wires can be short at this step, since you will be extending the run of wire by making an extension cord later.
Pay close attention to how you solder the wires and make the connector:
Here is how the board should look like after soldering. The ridges are not visible in the photo, but they are facing up.
To test for continuity, insert headers / DuPont wires into pins 1 and 2 of the JST connector, and attach the other side of said wires or pins to your multimeter's alligator clips. Set the multimeter to resistance / continuity test mode. When depressing the fan button, there should be continuity. Repeat the test for pins 3 and 4 with the LED button.
Ignore the rest of the board. We don't care about its electronics any more.
The fan connector is a CLIK-MATE standard connector. We'll replace this since we're using JST connectors.
FIXME crimping instructions and photos here.
The pinout of the fan, and the corresponding position of each cable in the JST connector, is as follows:
Just follow the official Prusa Research instructions specific to fan assembly and installation. We'll route the fan cable later — you need it loose for the test you'll perform now.
Once the fan is installed, connect 24 volt power to pin 1 (negative) and pin 2 (positive) of the fan's JST plug. You can use the DuPont / header pin trick to supply power to the JST plug.
If you use the Prusa Research PSU to supply power, remember that the outside of the barrel plug is negative, while the inside of the plug is positive (double-check this with your multimeter and the polarity label printed on the PSU).
When you supply power to the fan this way, the fan should spin at its maximum speed sucking air through the filter and pushing air through the exhaust holes. If the fan doesn't spin or it spins backwards, you have an issue you must fix in your connector.
Long story short: if I'm going to govern the filtration fan and the LED strip using both Home Assistant and the front panel, I need to know that:
The best way to see this at work is to assemble an initial prototype using a breadboard. This prototype contains the bare basics to:
One small problem: I don't yet have the relays I ordered. So, as stand-ins for the relays I ordered but don't yet have, I used some old school LEDs (with resistors to prevent ESP voltage from frying them).
I put together the circuit, then flashed the programming code once via USB. Once flashed, I first disconnected the USB cable and then powered the circuit using a 24 volt DC supply. When the XTVTX was running and online on my Wi-Fi network, I added it to Home Assistant the usual way (that is, via autodiscovery on Home Assistant's Devices & Services screen).
Use the following tabs to see how the prototype looks, how it was put together, and how it was programmed:
Here's how it's all hooked up:
3V3
and GND
on ESP32 to bottom rails (positive and negative, respectively).D24
and D25
).D33
and D32
to one side of each push button each.Here's the test circuit, divided into two photos:
And here is the source code for the ESP's programming, which you can copy and paste into your ESPHome editor:
substitutions:
name: button-tester
friendly_name: Button tester
esphome:
name: ${name}
friendly_name: ${friendly_name}
name_add_mac_suffix: false
esp32:
# XTVTX ESP32 (wroom)
board: nodemcu-32s
framework:
type: arduino
# Enable logging
logger:
level: debug
# Enable Web.
# Turn me off and enable below.
web_server:
port: 80
include_internal: true
local: true
# Enable Home Assistant API
api:
encryption:
key: "<use a key generated by ESPHome>"
ota:
password: "<use an OTA password generated by ESPHome>"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
button:
- platform: restart
name: Restart
entity_category: diagnostic
icon: mdi:restart
- platform: safe_mode
name: Safe mode restart
entity_category: diagnostic
icon: mdi:restart-alert
sensor:
- platform: wifi_signal
name: "Wi-Fi signal strength"
update_interval: 10s
entity_category: "diagnostic"
- platform: internal_temperature
name: "Device temperature"
update_interval: 10s
entity_category: "diagnostic"
binary_sensor:
- platform: gpio
icon: mdi:button-pointer
internal: true
pin:
number: GPIO33
mode:
input: true
pulldown: true
name: "Camera light switch"
on_press:
then:
- light.toggle: camera_light
- platform: gpio
icon: mdi:button-pointer
internal: true
pin:
number: GPIO32
mode:
input: true
pulldown: true
name: "Advanced filtration system switch"
on_press:
then:
- fan.toggle: advanced_filtration_system
output:
- platform: gpio
pin: GPIO26
id: "out_1"
- platform: gpio
pin: GPIO25
id: "out_2"
light:
- platform: binary
name: Camera light
id: camera_light
output: out_1
icon: mdi:led-strip-variant
fan:
- platform: binary
name: Advanced filtration system
id: advanced_filtration_system
output: out_2
icon: mdi:air-filter
My prototype was indeed successful — activating and deactivating the "light" and the "fan" via Home Assistant worked, and pushing the buttons on the base board toggled "light" and "fan" respectively.
Sadly, I'm missing a few components to make the circuit fully functional. But don't worry! Stay tuned to this very blog post for updates as parts arrive and the final circuit comes together.
The following is an archive of a thread by James Lindsay on Twitter, with edits mine.
Necessary context: as this thread unfolds, millions of illegal aliens have invaded the United States over the past three years. This is criminal activity, yet the U.S. government not only turns a blind eye to it, but in fact deliberately funds a lot of this activity¹ through nonprofit fronts (for some reason, the European Union funds those nonprofits a lot as well), and has threatened to punish U.S. state law enforcement trying to stem the oceans of people coming through the border.
We can therefore rule out this crisis being accidental, as the nation's news media quickly moves from the phase "it's not happening" to the "and we're so happy it is, bigot" phase.
¹ An archive of this video can be seen here.
The main things [the Biden regime] is importing with the border disaster are a crisis and, crucially, class struggle, which America mostly lacks.
Marxism is a manipulative ideology built on class struggle. If you don't have a permanent underclass, though, you lack a key ingredient to spark the chaos needed for Marxist takeover. You'll have to import one, then activate it. Then the explosive violence can begin. That's the border.
The factors that can make this sequence of events take place are:
The crisis part is simple: a crisis — the most beloved tactic of Marxists everywhere — forces a reflexive environment and an urgent shitty solution, which might get them their Democrat voters. There is precedent for this, as Reagan legalized the residence and subsequent nationalization of enormous amounts of illegal aliens, which directly led to California permanently becoming Democrat. We already have AOC on record saying that, in order to "solve" the illegals problem, what must be done is "legalize them".
What's really coming, though, is a massive citizens vs. aliens class struggle. Here's how we know this:
The framing of that struggle is Critical Immigration Theory. This is a form of Critical Theory of Identity that is already popular. If you've heard people discuss and defend the migration crisis by using abstract platitudes like "human rights," "global citizenship," and "no person is illegal," or if you've seen manipulative arguments used to suppress any opinion that opposes illegal mass migration, you witnessed Critical Immigration Theory in action.
Naturally, this framing is all nonsense (people don't just have a "right" to barge into your land, there's no such thing as "global" citizenship, and it is obvious that many people can and do commit illegal actions such as trespassing), but the fact that it's nonsense is irrelevant — all that matters is that the nonsense is meant to push the materialist conflict forward.
Why is this framing even necessary, though? The framing is necessary because, ordinarily, your average cultural Marxist or NPC brainwashed by CRT would never accept mass immigration on his own. Normally, the bourgeois Leftist would see illegal immigrants as leprous interlopers and threats to their economic interests, physical security and social stability.
Critical Immigration Theory will fix that. This Theory is a necessary ingredient because it mixes socioeconomic oil (bourgeois Leftists, especially intellectuals) and water (illegal aliens). It's like soap or any other surfactant — one end of the molecule mixes with water and the other with oil, enabling an emulsion. Explicitly stated: the Leftist intellectuals need a social theory to make the public accept foreign aliens as a basis for a class struggle that normally stands against them, and to make them believe (falsely) that the aliens and the Leftists are both on the same side of the struggle.
Critical Race Theory works this way too. At heart, it's a materialist (grifter) theory begging for affirmative action, handouts, welfare, and reparations, posing as a social theory that manipulates rich Leftist white guilt. That gets racist white Leftist elites to advocate for it, despite the fact that CRT explicitly wants their destruction.
—"We're on your side!" — "But we're not on yours"
What the regime is doing, is importing the practical basis for a brand new Marxist class struggle that blends Marxism, Marxist Third-Worldism and Postcolonialism, Marxist Environmentalism, and Marxist Critical Race Theory themes, so the Left intelligentsia will advocate for it.
If you want to know how that looks like, current-year Europe is a preview.
The flying car had been invented by the 1930's. A flying craft that could be piloted by teenagers, stored in a double wide garage, and take off from a residential street.
They should sell for $1-5K each new today. The State strangled their makers out of existence. (The excellent book Dude, where's my flying car? chronicles this.)
Every time I bring this up I'll hear someone say "They're dangerous! It's good we don't let kids from the hood fly these for $5K in their teens. Imagine what injuries and crashes would cost"
Here's the thing, though... basically every plane crash is nearly fatal. They're like motorcycles: either you respect them, or you very quickly pay the ultimate price. Because of that, the actual external costs of single-occupant plane crashes (much like motorcycle crashes) are very low — a one-time instantly fatal crash that 75% of the time hits nothing (the vast majority of the Earth, even near major cities, is unoccupied parking lot or field). Contrast this with bad automobile drivers, eternally causing crashes and involving others in their rolling liability.
So the real cost of letting people choose their own risk and make their own decision... is them choosing their own risk and making their own decision you may not like!
This faulty reasoning replicates across so much of modern life.
Smoking has already been banned in the vast majority of public settings and indeed the U.K. is gearing up to ban it entirely, even as most places have legalized equally carcinogenic cannabis. Nicotine itself doesn't cause cancer (the patches, vapes and gums don't); the cancer comes from breathing burnt smoke itself, which is the same with marijuana smoke.
This prohibition is justified on health grounds, and if you object "But my body my choice" the longhouse matriarchy we live in will screech that you cost the public healthcare system money, so it's not your choice, it's the healthcare system's...
...Except this is complete bullshit. Someone who dies of 99% fatal lung cancer at 70 saves the healthcare system and public coffers in general potentially millions. Right as they'd stopped working and contributing, they die. Instead, if they didn't smoke they might have lived to 98, have taken 28 more years of social security and retirement benefits, required treatment for maybe a half dozen lesser cancers, and new hips and knees along the way. By selflessly choosing to smoke and look cool and be more skinny/productive, this smoker has not only increased their productivity and positive externalities to the community, they've also saved the welfare state millions of dollars in lifetime benefit costs.
Why is "my body, my choice" not acceptable for smoking in private, but totally real for these much sicker people that cost the healthcare system way more than smokers?
So why are they actually banning smoking if the stated reasons are bullshit?
Because the modern longhouse State gets all of its legitimacy from the decrepit cry for "safety".
Same reason there is now a push to bloat motorcycle insurance costs — in many jurisdictions you cannot simply buy liability insurance on a motorcycle, but all insurance companies are mandated to tack on Injury insurance, loss of wages insurance, lifetime disability insurance... such that the total cost of these extras vastly exceeds the actual liability insurance you are required to have for the road.
Again, motorcycles are disproportionately driven by 50-70 year old men; people whose untimely death or loss of lifespan would actually save the system money. Some screeching bureaucrat might claim you're imposing costs on the system with your motorcycle injury... but statistically no, you're generating net savings... numbers the bureaucrat certainly hasn't crunched.
The real reason we can't smoke, fly privately, and increasingly are discouraged from biking —the real reason progress is stalled — is because in the absence of any meaningful external enemy, the only way the State can justify itself and its expansion is via nannyism and protecting the people "from themselves". The stated reason for the State existing is to protect you, and if there isn't a scary other threatening to invade and kill you, its legitimacy is dependent on artificially creating a society terrified of their own agency.
It is a perfect self-licking ice-cream cone. The State must exist and expand to protect your life and liberty... from your own life and liberty.
For this absurdity, flying cars have been uninvented; for this, the romantic waft of smoke in a dimly lit room is fast becoming extinct; for this, the wind in the hair, the joy of life is being extinguished. For this invention itself has been destroyed.
So, remember: every time you are seen to take risk, to strike out, to spread your wings, or to light your match — you are implicitly denouncing the State.
An inheritance tax is a special kind of evil.
You're not just robbing the dead.
You're robbing children.
Worse yet, you are robbing those who are about to die of the entire sense of their life's purpose.
It is the most basic of human instincts, to want to pass on what we have created, to want to make more lives, to love them even more than we love ourselves, and to want to leave them a better future than the life we had. In a voluntary world, it would be the most normal of affairs to beget those creations to one's family, friends, and most beloved endeavors.
Yes, there are those who do not feel this urge, whether that's because of psychological scars from a troubled past, or simply having another direction in life. I have nothing to say against those people. They find other ways to contribute to a better future, and we will find others way to care for them when they are old.
But someone has to make more humans, and someone has to love them enough to want to make the world better for them than it was for us. Otherwise, what is the point of the human race, of the Universe, of literally anything?
A legacy is not just money. It's not even just the family business, or the family farm, or family heirlooms. It's even more than a sense of connection to our past. It is the visible, tangible evidence, whether it is a little or a lot, that we existed, that we were loved by those who gave us life, that we were not a misfortune or an accident, that we belong with the world and there is a place for us in it.
It would be unthinkably cruel to rob even the wealthiest and most privileged of the younger generation of this. But what's crueler still is to selectively rob the middle class, the kids who are only inheriting a little, and have neither sophisticated knowledge of the tax code, nor lawyers and accountants on speed dial.
Every scheme for government-sponsored robbery is sold with claims of being a new version of Robin Hood, stealing from the rich to give to the poor.
But Robin of Locksley didn't steal from the rich to give to the poor. He stole from tax collectors and gave back to their victims. And he didn't work for the government. Furthermore, every one of these schemes, even the most sophisticated, requires some level of destruction of wealth every time someone parts ways with their loved ones.
Yes, it's true, there are some among us who will receive no legacy other than their parents' love. Some people don't even get that. It's an everyday tragedy, and one of the struggles of civilization is to find ways to give opportunities to those who were born with the talent to use them and nothing else.
But plundering and destroying our civilization's accumulated storehouse of wealth, of knowledge, and of love for future generations — no.
It is a great evil.
This evil is brought about by equalists who are obsessed with (quite explicitly, they don't hide it) sculpting the blank slates that they fervently believe in, but reality never brought about.
It is an atrocity.
And it has to stop.
Are you a Silicon Valley super-magnate with a billion-dollar fortune, or appreciable fraction thereof?
Were you born into the investor class, with red-carpet access to Ivy League universities, and plenty of family and social circle seed money to build your business once you graduated?
Did learn entrepreneurship and business management at your parents' knees from the moment you understood the concept?
Do you feel a vague sense of existential guilt because you realize that the world is full of talented people who didn't get the chances you got?
DO. NOT. ADVOCATE. COMMUNISM. See a therapist instead.
You could also endow some charities and scholarship funds and stuff, but most importantly, see a therapist.
Your vague existential guilt is not a call to change society. It is just your personal problem, one of the ver y few personal problems you have. It's a problem that exists in your head, so you must solve it in your head, not by ruining your entire civilization just so you can feel like you are "doing something".
The problem of lack of opportunities for talented members of the underclass has always existed (ask me how I know), and you are not going to solve it just by thinking about laws for five minutes.
It ain't that fucking easy.
Solving society's "forever problems" is not as simple as building a profitable website in an office in Palo Alto, CA.
Typically the only thing that permanently removes a problem from the human experience is a new piece of technology. Not a new political philosophy. And especially not an old, failed one.
Communism does not level the playing field. It sets the playing field on fire, and removes the ball.
And the middle class are not chess pieces for you to move around so you can solve your emotional problems.
You should not be ashamed of having hundreds of millions of dollars. Instead, you should be ashamed of being a mother fucking communist in 2023.
In 1845, there was plenty of excuse for being a communist. They didn't know any better. They had no idea how terribly everything would go wrong, how high the mountains of corpses would be stacked.
In 2023, you have to be a lunatic or a psychopath. What kind of person looks at 100+ years of mass slaughter, torture, rape, starvation, and brutal totalitarian regimes, and says "yeah, but maybe we could try just a little bit of that, and see how it goes?"
We've seen how it goes. It goes straight to hell, without the luxury of a handbasket. The experiments are over, and the results are in.
The middle class, and the Trumpenproletariat, knows that. They know perfectly well that communist ideas will be sold under a banner of "soak the rich", but weaponized against them, instead.
Do you think I am being rude to you? Do you feel like that's off limits?
It's not, and that's the whole point. For you, this is a genteel discussion of hypotheticals; if you lost 95% of your net worth, you'd still eat steak and fly business every day. For Middle America, or Latin America, or even most of Europe's people, it's an existential threat.
That's why some of y'all are getting sent pictures of your front doors. Because people who live in a double-wide just outside of Topeka, Kansas have a far better grasp of the ground truth of the early 21st century than you do, and they are trying to tell you that the days of genteel discussion of hypotheticals are over, at least for a while.
Because while you putter around with abstract ideas to make society "more fair", they are struggling to survive, wondering if their nation can be saved, and trying to think of ways to do so without resorting to a civil war that would rapidly turn into a Rwandan style machete party.
I don't want that. You don't want that. Even they don't want that. But if you keep doing this bullshit of advocating for Communism, we are all going to run out of alternatives.
So will you please, for the sake of your nation, your civilization, and your families and children, please stop maxxing charisma and intelligence, and start putting some experience points into wisdom?
Thanks.
It is the entire culture surrounding "captains of the Tech Industry", from birth, that makes them into Champagne Communists.
Autism adjacent techie nerds who managed to make millions or billions off a website, without ever seeing Middle America or what's happening there, are confused by the regular reality of regular folks.
They start to move in elite circles, get lots of attention online, and they start to think about how society should be ordered to maximize some sort of vague goodity-ness.
And then their brain just treats this problem like coding a website for streaming video games. You make up a really smart plan, and write the code, and all the little components execute the code, and some new feature is added, increasing the amount of goodity-ness in the world. Yay!
But societies aren't made of components waiting for instructions. They are made of people, who have their own goals and needs. And laws aren't computer code. They don't make people do things. Instead, they send men with guns to kidnap people and lock them in a concrete box for years or decades.
And autistic-adjacent nerd boys who were born into the investor class, and never had to contend with the physical horrors of being a target of the State, don't fully realize that. Their ability to identify with others is already stunted, and they simply cannot empathize with people they can't see.
So they say really wild stuff about how they want to change the JavaScript of society to add this or that feature. They really do believe that they can organize society as if it was a game of SimCity 2000 (don't forget to fund those roads to 100%!)
It's no different than the conversations they had in Harvard or Yale or MIT, usually while high: "Bro, like, what if we just took children at birth, and randomly assigned them to different families? Wouldn't that end racism?" They're not literally contemplating tearing an infant from his mother's arms. They haven't thought that far ahead. They're just slinging the shit with their bros.
But when they leave college for the Silicon Valley tech bubble, it doesn't feel all that fundamentally different, but it is. The difference is that, if and when you hit it out of the park, business-wise, people, especially other powerful people, start to regard you as not only a grown-ass man, but a leader and a thinker whose opinion matters.
So when one of them, still high on the same weed he was smoking in college, says "let's take away all the inheritances, put them in a big pool, and distribute them evenly", and other autistic tech nerds listen and discuss the idea, then certain people on the other end of the country, inside the Beltway, start to rub their hands together gleefully, and drool a little bit. These fellows are not autism-adjacent — they are psychopath-adjacent. They just want to get their hands on all that money, and if midwest farm families get dragged off their land by National Guardsmen, hell, that's a bonus, because that right there is their pornography. (Who had all those children at Waco killed? Yep. That's correct.) Paying some of the peasants minimum wage to beat, shoot, and kidnap the rest is what they get off on.
So they love it when naive public figures start to experiment with totalitarian communist ideas. It normalizes these ideas. And if that happens, they are waiting to pounce.
Your standard Silicon Valley Commie billionaire, in person, is probably a perfectly nice kid, if a little wet around the ears. But when they start playing with dynamite in public, it is necessary for all of us to quickly intervene.
Humiliating wealthy Communists is not strictly the goal — just a necessary side effect. After all, they suffer a lot less than an orphaned 19 year old being dragged out of mom and dad's house because it now belongs to the State.
So-called "captains of the Tech Industry" need to learn to read the room, and not suggest utopian authoritarianism in the very decade that Middle America is disenfranchised, despised, and bleeding from the pocketbook because the political class has been robbing them since before they were born. Ideally, they'd learn a bit about the history of totalitarianism before they hash out their totalitarian plans in public too.
But that's not the goal, either. The goal is to make insane totalitarian nonsense embarrassing and disqualifying to suggest.
"Anti-vaxxer" is a slur.
The term "anti-vaxxer" is used to undermine individual autonomy by critiquing personal health choices as socially irresponsible.
The term "anti-vaxxer" is used to marginalize parental concerns, casting doubt on the sincerity of guardians prioritizing their children's health.
The term "anti-vaxxer" is used to suppress the stories and experiences of individuals who have had genuine adverse reactions to vaccines.
The term "anti-vaxxer" is used to oversimplify complex scientific debates into black-and-white dichotomies.
The term "anti-vaxxer" is used to obscure the historical and socio-economic contexts that inform diverse attitudes toward vaccination.
The term "anti-vaxxer" is used to conflate skepticism about pharmaceutical industry practices with opposition to vaccinations themselves.
The term "anti-vaxxer" is used to sidestep systemic issues, such as access to healthcare and information, placing the burden of public health solely on individuals.
The term "anti-vaxxer" is used to disregard the role of informed consent in medical interventions.
The term "anti-vaxxer" is used to create a false sense of consensus by ignoring the medical community's internal debates and disagreements.
The term "anti-vaxxer" is used to weaponize science against dissenters, even when their positions may have scientific backing.
The term "anti-vaxxer" is used to propagate fear, implying a direct threat without acknowledging the diversity of reasons people may delay or decline certain vaccines.
The term "anti-vaxxer" is used to pressure individuals with blanket policies, without regard for individual health nuances and contraindications.
The term "anti-vaxxer" is used to fuel media sensationalism, often prioritizing clicks and views over balanced reporting and discussion.
The term "anti-vaxxer" is used to polarize public opinion, creating a wider social rift and less cohesion on public health strategy.
The term "anti-vaxxer" is used to deflect critique from vaccine policies and their enforcement, placing the spotlight on the public instead of policymakers.
The term "anti-vaxxer" is used to discredit any adverse event reporting related to vaccines as hysteria rather than a genuine safety signal.
The term "anti-vaxxer" is used to prioritize the vilification of certain groups over the pursuit of empathetic public health communication strategies.
The term "anti-vaxxer" is used to cast ethical and philosophical beliefs about medical interventions as illegitimate or unworthy of consideration.
The term "anti-vaxxer" is used to amplify the voice of the Big Phama while silencing the minority, negating the essentials of a democratic discourse in healthcare policy.
This is a transcript of a thread written by Jonathan Shedler on Twitter, with minor changes made.
One of most important things I've learned:
Severe personality problems find camouflage. No one thinks "I'm a sadist" or "I'm a malignant narcissist". Rather, they find a belief system / social group that validates their most hateful, destructive impulses, then construes them as virtues.
The most toxic and hateful people in the world are 100% convinced they fight for what is true and right. They find a way to give free rein to their cruelty, to attack, to treat others cruelly and viciously. And they find allies to cheer them on who also believe they are on the side of all that is true and good.
For psychologists looking for a more theoretical explanation, the psychological processes are:
Splitting means not recognizing one's own capacity for hate, cruelty, and destructiveness. The person is blind to the bad in themselves. Instead, they project the badness onto some designated other.
And this other person, via the defense of projection, is now seen as the repository of all that is bad and evil and necessary to destroy. That's the projection. The person now feels fully justified in unleashing their viciousness and hate on the other person, who is now seen (via projection) as someone monstrous who must be destroyed.
If the person who is projected on responds to the provocation with anger, this is now seen as further confirmation of how hateful and destructive they are (this is what is called is projective identification).
The end result is that the person can deny their own sadism, cruelty, and hate—while simultaneously acting it out without restraint — and feel themselves to be 100% on the side of truth and righteousness as they do it.
Example:
— "Did you read about Hunter's laptop? So much crime is revealed in the e-mails therein"
— "Haha, that's Russian disinformation."
Check out this clip:
I love that experiment! Even monkeys understand trade.
Moreso, monkeys also get the differences in value between goods! As soon as Monkey #1 realizes he is getting an inferior good (cucumber yuk, grape yum) for the same price, he immediately and forcefully rejects the trade, displaying frustration and anger.
Bravo! What a great experiment!
Videos shown to New Prague school staff depict white people as mosquitoes and inherently biased against black people.
“Just imagine, instead of being a stupid comment, a microaggression is a mosquito bite,” one of the videos teaching about microaggressions says. It goes on to explain that some people are bitten by “mosquitoes” a lot more than others.
Find the video below:
Oh — do note how at the very end they chop up the "mosquito" to pieces. What do you think that means?