-
-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HASS Integration #566
Comments
Additionally, it would be beneficial to have a message or topic that monitors the global on/off status of Playnite, allowing us to verify if it’s running. This would help ensure proper synchronization and control. |
This is amazing! It is interesting, because my primary purpose for creating Playnite Web was to automate my game room experience; with Playnite Web being the most overpowered "remote control." It has been challenging to do this while also keeping the wider appeal of sharing games without needing automation control. This is not documented, and I've been meaning to create a blog post about it, but you can integrate Playnite Web with Home Assistant already today. This is assuming that Playnite Web is the dashboard/touch point for interacting with the system as opposed to a Home Assistant dashboard. I hope that Playnite Web is a better experience to find and select a game to play that a Home Assistant dashboard, but that I also understand that may not be widely agreed upon. Playnite Web has some features locked behind a single user login. You provide the username, password, and secret via environment variables. If this is done, then you will be able to sign into Playnite Web. Once signed in, the game details page has a Play on platform button (shown below). Clicking this button publishes an MQTT message. However, that message is not picked up by the Plugin. This is because there may be additional automation needed prior to starting a game, such as turning on devices, setting volumes, etc. I have Home Assistant trigger a start game activity from the published message. This turns on the TV, AVR, sets inputs and volumes, etc.; letting Home Assistant handle the automation aspect. For PC games, when starting a game, I publish MQTT message from Home Assistant that runs a shell command on my PC to start Playnite.Desktop.exe with the game's ID as a CLI parameter. This starts the game. I also track the game's process ID back in Home Assistant. I do all of this with HASS.agent, which runs over MQTT. For PlayStation games, I use a custom ps5 mqtt docker service. This is the foundation of the ps5-mqtt version, which is not more feature rich, and I plan to replace mine with one day soon. Overall, this is a working way to start, stop and restart games. Unfortunately, it does not provide me with the controls to adjust the volume, use a different volume preset and other things that are found exclusively in Home Assistant. How to bridge that game is something I have not ironed out quite yet. All this works well, but none of the messages from Playnite Web's start, stop, restart actions are openly available in the documentation yet. As I said, it is something on my radar, but I just haven't done it yet. If this sounds like a solid approach to automation, then let's work towards using Playnite Web as the "remote" so to speak. If not, then that is ok, too. The entire reason for adding the graph API was to allow others to build their own experiences. One note on this is: my vision is for the graph API to be the extension point versus the messages coming from the Plugin. This is one reason I've started a real-time subscription model for the graph API. Nothing is stopping others from using those messages of course, but I do not intend on breaking changes to them bumping the major version, so if there are breaking changes you may not know based on the version number. What I'm about to say is more work, but the translation of games into messages that HA discovery understands could come from an external service; one that listens to the graph API and publishes changes? This will need the graph API to be leveled up some, but I'm not sold on the Plugin publishing what would directly become entities to Home Assistant. I'm a perfect example of not wanting that functionality. Alternatively, there could be a setting in the Plugin to enable or disable that feature. In either case, this is a great discussion to have and iron out and I'm happy to have someone interested enough to help solve it. |
This is a great idea. I'll add this as an issue. Currently, I always try to kill Playnite and start it fresh via my automation. However, knowing if it is running or not is a good feature to have. |
As a follow up to my long post, what do you think about having Playnite Web act as the remote control and leveling up its capabilities in this regard versus having games show up as entities in Home Assistant? Knowing this and how others feel will help guide the solution. Also, I'm not opposed to defining a structure somehow to make this work. It will simply mean breaking changes to the messages will need to be reflected in the release version. |
I've already explored the Playnite Web plugin's code and implemented a HASS Python integration that subscribes to the Playnite MQTT topic. The integration creates game switches based on MQTT discovery events, allowing users to start and stop games via Home Assistant. While starting a game works fine, stopping a game via MQTT doesn't stop the actual game, which I suspect might be a Playnite-side issue. A major challenge has been maintaining an accurate state for the switches. If we could access a persistent state of the running game process (using game IDs), it would greatly improve the reliability of the integration. I'm not familiar with Playnite's internal workings, but it would make sense if a process list was maintained internally, and if that could be published over MQTT, it could be used to reflect the real-time state of games within Home Assistant. I'd love to hear your thoughts on collaborating to ensure consistency in how MQTT messages are structured between our implementations. As an alternative, a direct Playnite Web plugin integration with MQTT device discovery would avoid the need for a custom integration and make things smoother overall. I realize this might be beyond current scope, but I’d be happy to contribute if needed. |
One area for improvement is the inconsistency in how releases are segmented by game ID, while commands are not. This creates confusion, especially when controlling multiple Playnite instances. In such a scenario, all instances would respond to a game start event, making it difficult to manage each instance independently. |
@cvele , this is a lengthy reply, so let me organize it to better communicate the ideas. I plan to talk about the following points, in this order:
General Response to HA IntegrationThis is amazing and I fully support this! There are some things Playnite Web can do to help make this easier to achieve from the integration's side. I'll explore this more in the brainstorming sections. Tracking Game StateNote that game state is already track-able via a few MQTT topics. When the game starts, stops, installs, uninstalls, etc. a message is published for each state. This message includes some game information, including the process ID of the game. I use these messages, for example, to set the currently running game process ID in Home Assistant. Stopping a Game: ChallengesI completely forgot Playnite Web's extension was subscribed to a start game topic. Unfortunately, there is no built-in Playnite API for Playnite extensions to stop a game. However, given the game's process ID is made available in some form, the process can be killed manually. Starting/Stopping a Game (the long way/work around) in my personal setupIn my setup, I opted to start a game via a MQTT message having a shell command to start Playnite's Desktop executable with a CLI parameter for the game ID. Both ways would work, but the benefit of using the shell command is that it doesn't matter whether Playnite is running already or not. If not, then it starts it, if it is, then there is a CLI parameter to stop other running instances. This requires a way to run this command on the host machine, e.g. I use HASS.agent (it also has a HA integration) to carry out this. However, I have not implemented a message to stop an already running game. Again, the reason is that the API provided for Playnite exposed to extensoins does not have this capability. With this said, I've gotten around this in a roundabout way. In home assistant I have a stored state (input_text) that is set on incoming MQTT messages for Playnite Web's game state topic. However, having just the process ID is not that helpful. But we can use the process' ID in a PowerShell command to kill that process. I do this by setting up a HASS.agent command that is invoked with PowerShell. The payload of the command is the PowerShell I want it to execute on the gaming pc. I then publish this message from Home Assistant when I need to stop the game. e.g. below: data:
qos: "2"
topic: homeassistant/button/gaming-pc/pwsh/action
payload: "-c \"Stop-Process -Id {{ states('input_text.current_game_process_id') }}\""
alias: Stop game process by ID
action: mqtt.publish To stop Playnite, I do the same but with Playnite's process ID. I got this information via subscribing to the MQTT message I set up in HASS.agent. The HASS.agent sensor is a PowerShell command that runs/updates every N seconds. For the script, I do something like Again, this is a roundabout way to achieve the goal and most certainly not easy for beginners that just want it to work. Hopefully, this provides some context that may inform us of a better solution. BrainstormingHow to Interface with Playnite WebThe first thing to consider is how we expect external systems to interact with Playnite Web. There are three ways on the table that I can see:
Graph APIThis was the intended mechanism to build custom experiences. There are some tangible benefits to using it, as well as some drawbacks. Note that although the Graph API may not support every feature today, the intention is for it to do so in the near future. With it you can track games states, start, stop, restart games, and, of course, query for game information. The biggest advantage here is the last one. Playnite web's API exposes games in a separate way than Playnite proper. There is an added concept in the graph that is not present in Playnite; the distinction between a game and a release of a game on a specific platform. For a specific example:
The above in Playnite proper, there are 4 games. The games look like the below
As you can see, the process of getting Playnite Web's relationships is not always straight forward. The PS games both have the same platforms, PS4 and PS5; even though one is on PS4 and one is on PS5. Note that this dynamic is not always consistent either. The last two we know are both PC (or computer), but if we wanted to play one, we would want to be able to pick which one from the two as they may have different saves, etc. The Graph API already does all the gymnastics to do this in a performant and extensible way. This is why it is the preferred way to interact with Playnite Web. However, the downside is that graph calls may not be the ideal way to receive the information, such as the HA integration makes it easier to work with MQTT directly instead. Internal MQTT MessagesAnother way is to directly subscribe to the MQTT messages of Playnite Web's extension. It also does some of the heavy lifting mentioned above, though not guaranteed to do all. The problem I see with this approach is that these messages are intended to be internal to Playnite Web. Even though they are on a message bus such that these messages can be consumed by other applications, the internal nature is not about preventing this, but more so that these messages will be customized for Playnite Web only. This means their shape can change without notice, as they were never intended to be consumed by others. There may be a middle ground to get a win-win. This is the third possibility I see. MQTT MessagesInstead of consuming the internal messages, there is nothing stopping us from publishing new messages on the message bus; ones that are not internal, but react to the changes, etc. from Playnite Web. This could be built directly into the Playnite Web's application for example. Another possibility is to create a separate process that does only this one job. It can subscribe to the graph API, which again is the preferred and most feature rich mechanism and translate all events into MQTT messages of whatever shape is ideal. Although it would be more compact to encorporate directly in the Playnite Web application (the web app code), I think I'd prefer it to not be baked in. My reasoning is that it is not really a responsiblity of Playnite Web and is more of a enabling a specific use case/experience. With that said, I do think this can be baked into Playnite Web's repository of code. This will enable automated publishes and releases with the rest of Playnite Web. This also means the tight partnership can mitigate breaking changes in the Graph API from impacting users while they wait for the MQTT message translation/publisher to be updated to account for said breaking changes. What do you think of this third approach? I would love to have this in the repo and aid in its development. I think this will buy you the precision of MQTT messages to power the HA integration, also, such as using the discovery format to automatically create game entities; each with their own associated actions to start, etc. Note, that pulling the HA integration into this repo is also a possibility that I'm not opposed to. Again, it may make the integration more responsive to changes within Playnite Web. This will also help users create automation for staring games beyond simply starting the executable on the host; such as turning on TVs, AVRs, lights, etc. This is because, with the above integration, these events can trigger these events in HA directly. I do think there is a need to separate the external start a game from the internal starting game executable. The reason is that users, such as myself, may want to turn on devices, TVs, AVRS, lights, ensure the remote host is actually turned on, etc. BEFORE the game executable is started. Stopping GamesThe above does not entirely address the stopping of games though. For this, I'm wondering if the Playnite Web extension does this, just not with the Playnite API. We could, for example, start a separate thread to kill the process by its ID from the extension. This would be ideal since it is already on the host gaming PC. This does account for other Platforms, such as PlayStations, though. There would need to be a conditional to check if the game to stop is running on the machine versus some other platform. The actual trigger would be an internal MQTT message; one that could also be translated to be used by other systems to stop other platforms, such as ps5-mqtt to stop PlayStations. Wrapping Up and FeedbackWhat do you think about the above proposals? If this lands as sounding like a good thing, then I can create some issues in GitHub. I think I may also create some ADRs (architectural decision record documents) in the repo to track major decisions like these. Future DiscussionsGiven the length of this reply and the lack of fluidity in collaborating, do you think GitHub issues is the right place for internal collaborators to collaborate? If so, then we can continue here. A while ago, I set up a Gitter (based on open-source MATRIX chat) to provide a place for the community to chat beyond GitHub issues. I chose this over Discord simply because Gitter used to be the mechanism for repos. However, I use Discord and many tech communities, such as the official React community, are on Discord, so I do not mind using it instead. Open to thoughts. If we decide on using Discord, then I'll need to update the README with the community links. One additional note, and in favor of Discord, is that @matt-quests-for-tacos and I use Discord when pair programming on Playnite Web already. Again, open to thoughts. |
Been postponing answering here as I was wrapping up the HASS integration for HACS (now available here: Playnite Web MQTT). I think one of the major issues here is the time zone difference. I'm based in CET, and if your time zone is offset significantly, pair programming might be a challenge. That said, there are a few different threads we need to pick up on, so I'll try to break them down for clarity. Playnite Web Architecture: The existing architecture involving Playnite, the Playnite Web plugin, and Playnite Web frontend (GraphQL API connected to MongoDB) feels overly complex for the task at hand. Hosting MongoDB just to interact with the Playnite Web seems like an unnecessary overhead. Ideally, the Playnite Web plugin could maintain an in-memory database, populated through MQTT instead of MongoDB, and request library information only when it needs to refresh or update a game. This would streamline the architecture and reduce the complexity. GraphQL API and Synchronization: While GraphQL adds a level of sophistication, it introduces synchronous requests and polling, which may not be compelling in this scenario. Given that our task revolves around game control and state monitoring, a message-driven approach (e.g., MQTT) aligns better with event-driven architectures like Home Assistant. Message Structure and MQTT Discovery: The current MQTT messages seem inconsistent, especially when it comes to game IDs and handling multiple Playnite instances. I agree that aligning with existing standards, such as Home Assistant’s MQTT discovery, would offer a lot of benefits, including automatic device discovery and better state management out of the box. A more consistent and standardized message strategy would improve integration reliability across different setups. On stopping games The inability to reliably stop games via Playnite is a roadblock, especially when dealing with platforms like Steam, where process IDs aren’t always consistent or accessible. Your approach of executing a PowerShell script to terminate non-whitelisted processes before starting a new game is a clever workaround, and I also integrate with HASS.Agent similarly. However, as you've pointed out, this is more of a hack than a proper solution. Ideally, the Playnite Web plugin should offer a more standardized way to handle this, perhaps through a built-in mechanism for terminating games, rather than relying on external scripts. Until something more robust is provided, pinning this topic seems like the right move, but we should definitely keep it on the radar as part of our longer-term goals. Let’s continue to explore how we can integrate this functionality in the future—whether through improvements to the Playnite Web plugin or some other solution that avoids the current tomfoolery we're resorting to. |
I’ve been exploring the creation of a Home Assistant integration, and so far, my approach involved hosting a solution on the HASS instance, using the API to display dashboards. However, this method introduces unnecessary overhead since it requires additional resources for relatively minor functionality. Additionally, it's limited to dashboards and user interactions via clicks, which prevents using voice assistants to start games.
Recently, I’ve come up with a new idea: building a custom Home Assistant integration that generates virtual switches for each game in the library, essentially replicating part of the Playnite Web frontend/API functionality. The concept is to subscribe to the Playnite Web MQTT topic and create switches based on game installation, uninstallation, and synchronization events.
My primary concern is ensuring this remains aligned with your work, @andrew-codes. Would you be open to collaborating or coming to an agreement on how the messages should be structured for consistency?
A cleaner solution that could avoid the need for a custom integration altogether would be to integrate MQTT device discovery directly into the Playnite Web plugin. However, I realize this might be beyond the current focus and scope. Here’s a link to Home Assistant’s MQTT device discovery documentation.
I’d love to hear your thoughts. I already have a proof of concept in place, although it’s not yet fully functional. Here's a glimpse of it:
switch.py
mqtt_handler.py
init.py
The text was updated successfully, but these errors were encountered: