There’s a vaporent community and a vaporists community. Neither have been active for almost a year. It would be nice to have one of those going to see what everybody’s using. I also miss the old old cult/ Franklin/thca groups from r/. Anyone interested in starting one of those?

  • JTskulk@lemmy.world
    link
    fedilink
    English
    arrow-up
    16
    ·
    7 months ago

    I have a volcano and a script I wrote to control it via a tasmota power plug. Now my computer plays a clip of snoop dogg when I turn it on and when it’s fully heated up. And it automatically turns it off at night if I forget to. I can turn it on from anywhere in the world. I think it’s cool, but who cares?

    • Frisbeedude@sopuli.xyz
      link
      fedilink
      arrow-up
      8
      ·
      7 months ago

      I think it’s cool, but who cares?

      We do! Please open-source it, king of stoner engineering!

      (I use the Plenty from time to time, but it kinda sucks)

      • JTskulk@lemmy.world
        link
        fedilink
        English
        arrow-up
        2
        ·
        6 months ago

        Ask and ye shall receive! I’m tacking a GPL 3 license to it. The plugs that play a sound after a delay won’t work on Windows because I use fork(), but I don’t use Windows because fuck Windows. It uses mpv to play sounds, but that is easily changed. AMA.

        #!/usr/bin/env python
        "Control my various tasmota devices. Licensed under GPL v3: https://www.gnu.org/licenses/gpl-3.0.en.html#license-text"
        
        import os
        from time import sleep
        import urllib.request
        from json import loads
        from subprocess import Popen
        
        __all__ = ["Tasmota", "TasmotaWarmup", "TasmotaOffFirst", "DEVICENAMES"]
        
        class Tasmota():
            "A tasmota device."
            def __init__(self, ipaddress: str, name: str=None):
                self.ipaddress = ipaddress
                self.name = name
        
            def __repr__(self):
                return f"<{type(self).__name__} {self.name if self.name else self.ipaddress}>"
        
            def _request(self, cmd: str) -> str:
                "make an http request to the device"
                return urllib.request.urlopen(f"http://{self.ipaddress}/cm?cmnd={cmd.replace(' ', '%20')}").read()
        
            def on(self) -> bool:
                "Turn the device on. return True if successful"
                return b"ON" in self._request("Power On")
        
            def off(self) -> bool:
                "Turn the device off. return True if successful"
                return b"OFF" in self._request("Power Off")
        
            def toggle(self) -> bool:
                "Toggle the device power. return True if power is now on, False if it's off"
                return b"ON" in self._request("Power Toggle")
        
            def status(self) -> bool:
                "return True if the device is on, False if it is off"
                return bool(loads(self._request("Status"))["Status"]["Power"])
        
        class TasmotaWarmup(Tasmota):
            "Plays a sound when started, plays a sound after a waiting period."
            def __init__(self, ipaddress: str, name: str=None, warmup_time: int=None, on_sound: str=None, ready_sound: str=None):
                "warmup_time is seconds, on/ready_sound is the path to the audio file to play"
                super().__init__(ipaddress, name)
                self.warmup_time = warmup_time
                self.on_sound = on_sound
                self.ready_sound = ready_sound
        
            def _playSound(self, sound: str) -> None:
                "play a sound"
                Popen(["mpv", "--no-terminal", "--volume=60", sound])
        
            def _beginPowerOnSounds(self) -> None:
                "Play a sound when turning on and another sound when ready"
                if self.on_sound:
                        self._playSound(self.on_sound)
                if self.warmup_time and self.ready_sound:
                    if __name__ == "__main__": # using this as a script, fork to background and return terminal
                        if os.fork() == 0: # wait in the background for the warmup_time
                            self._sleepAndPlay()
                            raise SystemExit
                    else:
                        Thread(target=self._sleepAndPlay).start()
        
            def _sleepAndPlay(self) -> None:
                "The actual sleeping and playing, to be run in a thread if needed."
                sleep(self.warmup_time)
                if self.status(): # if device is still on
                    self._playSound(self.ready_sound)
        
            def on(self) -> bool:
                "Turn the device on and play sounds"
                if super().on():
                    self._beginPowerOnSounds()
                    return True
                return False
        
            def toggle(self) -> bool:
                "toggle the status and play sounds if we're turning it on"
                if super().toggle():
                    self._beginPowerOnSounds()
                    return True
                return False
        
        class TasmotaOffFirst(TasmotaWarmup):
            "A Tasmota object that turns the device off first before turning it on"
            def _turn_off_before_on(self) -> bool:
                "Turn this device off first if it's already on when it's switched on"
                if not super().toggle(): # if toggling turned it off
                    super().on()
                return True
        
            def on(self) -> bool:
                return self._turn_off_before_on()
        
        class TasmotaAlwaysOn(TasmotaOffFirst):
            "This Tasmota class is always on; toggling it will turn it off briefly and then back on"
            def toggle(self) -> bool:
                "toggle this device off and then back on again"
                return self._turn_off_before_on()
        
        DEVICENAMES = {"volcano": TasmotaWarmup("192.168.1.152", "Volcano", 355, "/home/jt/.sounds/hold up hey.ogg",
                                                "/home/jt/.sounds/fill that bag up right now2.flac"),
                           "towel": TasmotaOffFirst("192.168.1.153", "Towel Warmer", warmup_time=(20*60)+30,
                                                    ready_sound="/home/jt/.sounds/yayeah.ogg"),
                           "radiator": Tasmota("192.168.1.166", "Radiator"),
                           "taco": TasmotaAlwaysOn("192.168.1.156", "Taco")
                           }
        
        if __name__ != "__main__":
            from threading import Thread # only needed when importing this module
        else:
            import sys, argparse
            parser = argparse.ArgumentParser(description="Control Tasmota wifi power plugs")
            parser.add_argument("devices", help="device(s)", action="store", nargs="*")
            operation_group = parser.add_mutually_exclusive_group()
            operation_group.add_argument('--on', '-n', help="power on device", action="store_true")
            operation_group.add_argument('--off', '-f', help="power off device", action="store_true")
            operation_group.add_argument('--toggle', '-t', help="toggle device power", action="store_true")
            operation_group.add_argument('--status', '-s', help="get status of device", action="store_true")
            args = parser.parse_args()
        
            # Sanity checks
            if not args.devices:
                print(f"No device specified. Available devices are: {' '.join(DEVICENAMES.keys())}", file=sys.stderr)
                parser.print_help()
                sys.exit(1)
            invalid = []
            for d in args.devices:
                if not DEVICENAMES.get(d):
                    invalid.append(d)
            if invalid:
                print(f"Invalid device{'s' if len(invalid) > 1 else ''}: {' '.join(invalid)}", file=sys.stderr)
                print(f"Available devices are: {' '.join(DEVICENAMES.keys())}", file=sys.stderr)
                sys.exit(3)
            for d in args.devices: # gogo
                t = DEVICENAMES[d]
                if args.on:
                    if t.on():
                        print(f"{t.name} turned on")
                    else:
                        print(f"Failed to turn on {t.name}", file=sys.stderr)
                elif args.off:
                    if t.off():
                        print(f"{t.name} turned off")
                    else:
                        print(f"Failed to turn off {t.name}", file=sys.stderr)
                elif args.toggle:
                    print(f"{t.name} turned {'on' if t.toggle() else 'off'}")
                elif args.status:
                    print(f"{t.name} is {'on' if t.status() else 'off'}")
        
    • sorrybookbroke@sh.itjust.works
      link
      fedilink
      English
      arrow-up
      4
      ·
      7 months ago

      That is wild, now I want a volcano. I’m more into handhelds and love my crafty+ but that’s wild enough to make me think about buying one

      • JTskulk@lemmy.world
        link
        fedilink
        English
        arrow-up
        2
        ·
        6 months ago

        Dude honestly the Volcano rules. I’ve had mine almost 20 years now and I’ve had a screw rattle loose and the plastic airflow button broke ($10 part) and that’s it. I also bought a Crafty+ and I hardly ever use it. The Volcano is definitely smoother and I think hits harder. Plus you can see how heavy your dose is about to be as the bag fills. The power plugs I bought came out to like $10 each I think for a pack of 4.

    • Shareni@programming.dev
      link
      fedilink
      arrow-up
      3
      arrow-down
      1
      ·
      7 months ago

      I can turn it on from anywhere in the world. I think it’s cool, but who cares?

      Inb4 burglars care because it can be used to track when you’re at home and when you’re away on a holiday

      I know the chances are far lower for custom stuff when compared to cheap IP cameras, but having anything open to the internet should leave you extra paranoid.

      • JTskulk@lemmy.world
        link
        fedilink
        English
        arrow-up
        2
        ·
        6 months ago

        It’s actually not open on the internet, it’s only on my LAN. I ssh in to access it if I’m out which is rare so it’s very safe. These Tasmota plugs are great because they use Free software firmware (which I updated from the web, not the manufacturer), I trust them a lot more than any other IOT device.