I live on the Gold Coast, Australia. My city council offers a web page where I can check for my waste collection schedule.
This github repo contains the implementation for an extensive list of locations around the world, in python, for homeassistant:
This below demonstrates using JRuby scripting to scrape the waste collection schedule from a web page.
I cheated a bit in my rule because I know my schedule is on Wednesdays. My city council collects the general waste every week, but alternate the recycling bin and green waste bin every other week. So I hard coded my rule to run on Tuesday, Wednesday and Thursday, to issue a reminder, and make a little icon on my wall display to appear on Tuesday and Wednesday, and disappear on Thursday. A different / better way of checking could surely be done.
# frozen_string_literal: true
# gemfile do
# source "https://rubygems.org"
# gem "faraday"
# gem "nokogiri"
# end
#
# Or configure the jrubyscripting addon to install these gems on startup
require "faraday"
require "nokogiri"
# Idea from https://github.com/mampfes/hacs_waste_collection_schedule
ANNOUNCEMENT_TIME = LocalTime.parse("7pm")
ADDRESS = "1 Cavill Avenue, Surfers Paradise"
module WasteCollectionSchedule
class GoldCoast
attr_reader :schedule
module Type
GENERAL = "General waste"
RECYCLING = "Recycling"
GREEN = "Green organics"
end
def initialize(address)
fetch(address)
end
def fetch(address)
conn = Faraday.new(url: "https://www.goldcoast.qld.gov.au") { |f| f.response :json }
response = conn.get("/api/v1/myarea/searchfuzzy?maxresults=1", keywords: address).body
unless (geolocation_id = response["Items"].first["Id"])
raise "No results found for #{address}. Check your address on https://www.goldcoast.qld.gov.au/Services/Waste-recycling/Find-my-bin-day"
end
content = conn.get("/ocapi/Public/myarea/wasteservices", ocsvclang: "en-AU", geolocationid: geolocation_id)
.body["responseContent"]
@schedule = Nokogiri::HTML.fragment(content)
.search("article")
.map do |element|
{
type: element.search("h3").text,
frequency: parse_frequency(element.search("div.subheading").text),
date: Date.parse(element.search("div.next-service").text.strip.split.last)
}
end
self
ensure
conn.close
end
def next_collection_date
@schedule.map { |item| item[:date] }
.select { |date| date >= Date.today }
.min
end
def next_collections
@schedule.select { |item| item[:date] == next_collection_date }
end
private
#
# Parse the frequency description and return the duration
#
# @param frequency [String] The frequency of the waste collection, e.g. "weekly", "fortnightly"
# @return [Duration]
def parse_frequency(frequency)
case frequency.downcase
when /weekly/ then 7.days
when /fortnightly/ then 14.days
end
end
end
end
# This is for mainui page to show an icon
items.build do
string_item Next_WasteCollection_Type, "Next Waste Collection Type", state: NULL
end
rule "Download rubbish bin collection schedule" do
on_load
every :tuesday, :wednesday, :thursday
only_if { Time.now.then { |t| t.tuesday? || t.wednesday? || t.thursday? } }
run do
if Time.now.then { |t| t.tuesday? || t.wednesday? }
schedule = WasteCollectionSchedule::GoldCoast.new(ADDRESS)
if Date.today.between?(schedule.next_collection_date - 1, schedule.next_collection_date)
type = schedule.next_collections
.map { |item| item[:type] }
.reject { |t| t == WasteCollectionSchedule::GoldCoast::Type::GENERAL }
.first
Next_WasteCollection_Type.update type
msg = "<speak>Bin day, bin day, <prosody rate='slow'>tomorrow is a #{type} bin day</prosody>, #{type} bin</speak>"
msg_plain = msg.gsub(/<[^>]*>/, "")
if Date.today.next_day == schedule.next_collection_date
Notification.send(msg_plain, id: "bin_day", icon: "ic:hugeicons:waste")
end
announcement_time = schedule.next_collection_date.prev_day.to_zoned_date_time.with(ANNOUNCEMENT_TIME)
if announcement_time > Time.now
after(announcement_time, id: Next_WasteCollection_Type) do
LivingRoom_Echo_TTS << msg
end
end
end
else
Next_WasteCollection_Type.update nil
end
end
end