Compare commits
4 Commits
ee6a150e3e
...
b82c9af8c4
| Author | SHA1 | Date | |
|---|---|---|---|
| b82c9af8c4 | |||
| f4e87910ab | |||
| b8b585d242 | |||
| b38067dd8c |
@@ -0,0 +1,637 @@
|
||||
mqtt:
|
||||
enabled: false
|
||||
|
||||
detectors:
|
||||
coral:
|
||||
type: edgetpu
|
||||
device: pci
|
||||
|
||||
ffmpeg:
|
||||
hwaccel_args: preset-nvidia
|
||||
|
||||
|
||||
record:
|
||||
enabled: true
|
||||
alerts:
|
||||
retain:
|
||||
days: 30
|
||||
mode: motion
|
||||
detections:
|
||||
retain:
|
||||
days: 30
|
||||
mode: motion
|
||||
|
||||
continuous:
|
||||
days: 0
|
||||
motion:
|
||||
days: 3
|
||||
go2rtc:
|
||||
streams:
|
||||
# Backbasement:
|
||||
# - ffmpeg:rtsp://tpadmin:Optimus0329@192.168.128.222:554/live/ch0#video=copy#audio=copy#audio=aac#hardware
|
||||
# SubBackBasement:
|
||||
# - ffmpeg:rtsp://tpadmin:Optimus0329@192.168.128.222:554/live/ch1#video=copy#audio=copy#audio=aac#hardware
|
||||
# FrontBasement:
|
||||
# - ffmpeg:rtsp://tpadmin:Optimus0329@192.168.128.223:554/live/ch0?token=e6cf2225e8bf5fb028543898fab9a545#video=copy#audio=copy#audio=aac#hardware
|
||||
# SubFrontBasement:
|
||||
# - ffmpeg:rtsp://tpadmin:Optimus0329@192.168.128.223:554/live/ch1?token=e6cf2225e8bf5fb028543898fab9a545#video=copy#audio=copy#audio=aac#hardware
|
||||
# Eningeering:
|
||||
# - ffmpeg:rtsp://tpadmin:Optimus0329@192.168.128.221:554/live/ch0?token=e6cf2225e8bf5fb028543898fab9a545#video=copy#audio=copy#audio=aac#hardware
|
||||
# SubEngineering:
|
||||
# - ffmpeg:rtsp://tpadmin:Optimus0329@192.168.128.221:554/live/ch1?token=e6cf2225e8bf5fb028543898fab9a545#video=copy#audio=copy#audio=aac#hardware
|
||||
Driveway:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch12_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubDriveway:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch12_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
Porch:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch8_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubPorch:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch8_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
FenceGate:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch1_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubFenceGate:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch1_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
GardenArea:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch2_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubGardenArea:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch2_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
Backyard1:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch3_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubBackyard1:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch3_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
Backyard2:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch4_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubBackyard2:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch4_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
Backyard3:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch0_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubBackyard3:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch0_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
Backyard4:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch10_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubBackyard4:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch10_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
Backyard5:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch7_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubBackyard5:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch7_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
PatioArea:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch6_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubPatioArea:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch6_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
PoolArea:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch9_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubPoolArea:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch9_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SideHouse:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch11_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubSideHouse:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch11_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
BackSlider:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch5_0.264#video=copy#audio=copy#audio=aac#hardware
|
||||
SubBackSlider:
|
||||
- ffmpeg:rtsp://admin:Optimus0329@192.168.128.11:80/ch5_1.264#video=copy#audio=copy#audio=aac#hardware
|
||||
|
||||
|
||||
cameras:
|
||||
# name_of_your_camera: # <------ Name the camera
|
||||
# enabled: True
|
||||
# ffmpeg:
|
||||
# inputs:
|
||||
# - path: rtsp://10.0.10.10:554/rtsp # <----- The stream you want to use for detection
|
||||
# roles:
|
||||
# - detect
|
||||
# detect:
|
||||
# enabled: False # <---- disable detection until you have a working camera feed
|
||||
# width: 1280
|
||||
# height: 720
|
||||
|
||||
# back_basement:
|
||||
# enabled: true
|
||||
# ffmpeg:
|
||||
# inputs:
|
||||
# # - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/BackBasement
|
||||
# #input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
# - path: rtsp://127.0.0.1:8554/SubBackBasement
|
||||
# #input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - detect
|
||||
# detect:
|
||||
# enabled: true # <---- disable detection until you have a working camera feed
|
||||
# width: 1280
|
||||
# height: 720
|
||||
# fps: 5
|
||||
# motion:
|
||||
# enabled: true
|
||||
# threshold: 30
|
||||
# contour_area: 30
|
||||
# mask: 0.683,0.006,0.683,0.056,0.766,0.055,0.996,0.054,0.996,0.006
|
||||
# improve_contrast: true
|
||||
# snapshots:
|
||||
# enabled: true
|
||||
# timestamp: true
|
||||
# bounding_box: true
|
||||
# retain:
|
||||
# objects:
|
||||
# person: 7
|
||||
# front_basement:
|
||||
# enabled: true
|
||||
# ffmpeg:
|
||||
# inputs:
|
||||
# # - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/FrontBasement
|
||||
# #input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
# - path: rtsp://127.0.0.1:8554/SubFrontBasement
|
||||
# #input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - detect
|
||||
# detect:
|
||||
# enabled: true # <---- disable detection until you have a working camera feed
|
||||
# width: 1280
|
||||
# height: 720
|
||||
# fps: 5
|
||||
# motion:
|
||||
# enabled: true
|
||||
# threshold: 30
|
||||
# contour_area: 30
|
||||
# mask: 0.723,0,0.724,0.05,1,0.048,0.999,0.001
|
||||
# improve_contrast: true
|
||||
# snapshots:
|
||||
# enabled: true
|
||||
# timestamp: true
|
||||
# bounding_box: true
|
||||
# retain:
|
||||
# objects:
|
||||
# person: 7
|
||||
# record:
|
||||
# enabled: false
|
||||
# engineering:
|
||||
# enabled: true
|
||||
# ffmpeg:
|
||||
# inputs:
|
||||
# # - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Engineering
|
||||
# #input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
# - path: rtsp://127.0.0.1:8554/SubEngineering
|
||||
# #input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - detect
|
||||
# detect:
|
||||
# enabled: true # <---- disable detection until you have a working camera feed
|
||||
# width: 1280
|
||||
# height: 720
|
||||
# fps: 5
|
||||
# motion:
|
||||
# enabled: true
|
||||
# threshold: 14
|
||||
# contour_area: 15
|
||||
# improve_contrast: true
|
||||
# snapshots:
|
||||
# enabled: true
|
||||
# timestamp: true
|
||||
# bounding_box: true
|
||||
# retain:
|
||||
# objects:
|
||||
# person: 7
|
||||
# record:
|
||||
# enabled: false
|
||||
driveway:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Driveway
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubDriveway
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
zones:
|
||||
drivewayview:
|
||||
coordinates: 0,0.373,0,1,1,1,1,0.381,0.47,0.343,0.134,0.352
|
||||
loitering_time: 0
|
||||
friendly_name: DrivewayView
|
||||
porch:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Porch
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubPorch
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
fence_gate:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/FenceGate
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubFenceGate
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
zones:
|
||||
fencegate:
|
||||
coordinates:
|
||||
0,0.395,0.318,0.259,0.598,0.175,0.916,0.237,1,0.296,1,1,0.003,0.996
|
||||
loitering_time: 0
|
||||
friendly_name: FenceGate
|
||||
garden_area:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/GardenArea
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubGardenArea
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
backyard_1:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Backyard1
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubBackyard1
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
zones:
|
||||
backyard1:
|
||||
coordinates:
|
||||
0.001,0.274,0.124,0.162,0.228,0.143,0.382,0.131,0.555,0.133,0.714,0.16,0.854,0.196,0.998,0.253,0.998,0.996,0,0.992
|
||||
loitering_time: 0
|
||||
friendly_name: Backyard1
|
||||
backyard_2:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Backyard2
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubBackyard2
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
zones:
|
||||
backyard2:
|
||||
coordinates:
|
||||
0.002,0.147,0.086,0.106,0.172,0.091,0.271,0.078,0.386,0.077,0.499,0.077,0.601,0.086,0.698,0.099,0.787,0.117,0.859,0.087,0.995,0.155,0.998,0.992,0.001,0.995
|
||||
loitering_time: 0
|
||||
friendly_name: Backyard2
|
||||
backyard_3:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Backyard3
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubBackyard3
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
zones:
|
||||
backyard3:
|
||||
coordinates:
|
||||
0.001,0.337,0.166,0.332,0.327,0.342,0.419,0.344,0.51,0.355,0.603,0.363,0.692,0.374,0.771,0.381,0.848,0.389,0.951,0.405,0.997,0.423,0.998,0.996,0.003,0.994
|
||||
loitering_time: 0
|
||||
friendly_name: Backyard3
|
||||
motion:
|
||||
mask: 0.79,0.539,0.845,0.541,0.82,0.858,0.772,0.844
|
||||
backyard_4:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Backyard4
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubBackyard4
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
motion:
|
||||
mask:
|
||||
- 0.866,0.001,0.866,0.209,1,0.202,1,0
|
||||
- 0.001,0,0.249,0.001,0.249,0.045,0.002,0.044
|
||||
threshold: 60
|
||||
contour_area: 10
|
||||
improve_contrast: true
|
||||
backyard_5:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/Backyard5
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubBackyard5
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
motion:
|
||||
mask:
|
||||
- 0.029,0.31,0.13,0.305,0.134,0.54,0.032,0.544
|
||||
- 0.004,0.002,0.004,0.044,0.245,0.044,0.244,0
|
||||
threshold: 60
|
||||
contour_area: 10
|
||||
improve_contrast: true
|
||||
zones:
|
||||
backyard5:
|
||||
coordinates:
|
||||
0.001,0.305,0.043,0.264,0.113,0.194,0.19,0.128,0.271,0.109,0.371,0.089,0.525,0.057,0.709,0.057,0.89,0.076,0.997,0.122,0.997,0.995,0.002,0.998
|
||||
loitering_time: 0
|
||||
friendly_name: Backyard5
|
||||
patio_area:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/PatioArea
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubPatioArea
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
pool_area:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/PoolArea
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubPoolArea
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
motion:
|
||||
mask:
|
||||
0.43,0.146,0.704,0.194,0.532,0.808,0.199,0.704,0.002,0.559,0.252,0.282
|
||||
back_slider:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/BackSlider
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubBackSlider
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
side_house:
|
||||
enabled: true
|
||||
ffmpeg:
|
||||
inputs:
|
||||
# - path: rtsp://tpadmin:Optimus0329@192.168.128.225/stream1
|
||||
# - path: rtsp://127.0.0.1:8554/SideHouse
|
||||
# input_args: preset-rtsp-restream
|
||||
# roles:
|
||||
# - record
|
||||
- path: rtsp://127.0.0.1:8554/SubSideHouse
|
||||
input_args: preset-rtsp-restream
|
||||
roles:
|
||||
- record
|
||||
- detect
|
||||
detect:
|
||||
enabled: true # <---- disable detection until you have a working camera feed
|
||||
width: 1280
|
||||
height: 720
|
||||
fps: 5
|
||||
snapshots:
|
||||
enabled: true
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
objects:
|
||||
person: 7
|
||||
record:
|
||||
enabled: true
|
||||
motion:
|
||||
threshold: 60
|
||||
contour_area: 40
|
||||
improve_contrast: true
|
||||
mask:
|
||||
0.001,0.859,0.085,0.717,0.203,0.637,0.383,0.736,0.65,0.421,0.642,0.997,0.003,0.999
|
||||
zones:
|
||||
sidehouse:
|
||||
coordinates: 0.661,0.001,0.662,0.996,1,1,1,0
|
||||
loitering_time: 0
|
||||
friendly_name: SideHouse
|
||||
objects:
|
||||
filters:
|
||||
person: {}
|
||||
version: 0.17-0
|
||||
@@ -0,0 +1,4 @@
|
||||
[credentials]
|
||||
username=<username>
|
||||
password=<password>
|
||||
IPMIEK=0000000000000000000000000000000000000000
|
||||
@@ -4,24 +4,55 @@ import re
|
||||
import sys
|
||||
import datetime
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
|
||||
# IPMI settings
|
||||
IPMIUSER = "<username>"
|
||||
IPMIPW = "<password>"
|
||||
IPMIEK = "0000000000000000000000000000000000000000"
|
||||
DEFAULT_EK = "0000000000000000000000000000000000000000"
|
||||
|
||||
# IPMI settings (loaded at runtime from credentials file)
|
||||
IPMIUSER = None
|
||||
IPMIPW = None
|
||||
IPMIEK = DEFAULT_EK
|
||||
|
||||
# Fan / temperature settings
|
||||
FANSPEED = 20 # percent
|
||||
MAXTEMP = 37 # Celsius
|
||||
|
||||
def build_ipmi_base():
|
||||
base = ["ipmitool", "-I", IPMIINTERFACE, "-H", IPMIHOST, "-U", IPMIUSER, "-P", IPMIPW, "-y", IPMIEK]
|
||||
if IPMICIPHER is not None:
|
||||
base += ["-C", str(IPMICIPHER)]
|
||||
return base
|
||||
|
||||
def has_ipmi_session_error(stderr_text):
|
||||
s = (stderr_text or "").lower()
|
||||
markers = [
|
||||
"unable to establish ipmi v2 / rmcp+ session",
|
||||
"rakp",
|
||||
"session timeout",
|
||||
"authentication type",
|
||||
"invalid user name",
|
||||
]
|
||||
return any(marker in s for marker in markers)
|
||||
|
||||
def run_ipmi(args):
|
||||
base = ["ipmitool", "-I", "lanplus", "-H", IPMIHOST, "-U", IPMIUSER, "-P", IPMIPW, "-y", IPMIEK]
|
||||
base = build_ipmi_base()
|
||||
cmd = base + args
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError(f"ipmitool failed: {' '.join(cmd)}\n{p.stderr.strip()}")
|
||||
if p.returncode != 0 or has_ipmi_session_error(p.stderr):
|
||||
raise RuntimeError(
|
||||
f"ipmitool failed: {' '.join(cmd)}\n"
|
||||
f"stdout: {(p.stdout or '').strip() or '<empty>'}\n"
|
||||
f"stderr: {(p.stderr or '').strip() or '<empty>'}"
|
||||
)
|
||||
return p.stdout
|
||||
|
||||
def run_ipmi_raw(args):
|
||||
base = build_ipmi_base()
|
||||
cmd = base + args
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
return cmd, p.returncode, p.stdout, p.stderr
|
||||
|
||||
def log_systemd(tag, msg):
|
||||
try:
|
||||
subprocess.run(["systemd-cat", "-t", tag], input=msg + "\n", text=True, check=True)
|
||||
@@ -34,33 +65,108 @@ def ts_print(msg):
|
||||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
print(f"{now} {msg}")
|
||||
|
||||
def get_ambient_temp():
|
||||
out = run_ipmi(["sdr", "type", "temperature"])
|
||||
# find lines like "Exhuat Temp | 29 degrees C"
|
||||
lines = [l for l in out.splitlines() if "Exhaust" in l and "degrees" in l]
|
||||
if not lines:
|
||||
raise RuntimeError("Exhaust temperature line not found in ipmitool output")
|
||||
# Extract last number found in the last matching line (like the original)
|
||||
field = lines[-1].split("|")[4]
|
||||
#ts_print("Debug: field =", field)
|
||||
m = re.search(r"(\d{1,3})", field)
|
||||
if not m:
|
||||
raise RuntimeError("Could not parse temperature from line: " + lines[-1])
|
||||
return int(m.group(1))
|
||||
def load_credentials(path):
|
||||
if not os.path.exists(path):
|
||||
raise RuntimeError(f"credentials file not found: {path}")
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(path)
|
||||
|
||||
try:
|
||||
username = config.get("credentials", "username", fallback="root")
|
||||
password = config.get("credentials", "password")
|
||||
encryption_key = config.get("credentials", "encryption_key", fallback=DEFAULT_EK)
|
||||
except (configparser.NoSectionError, configparser.NoOptionError) as e:
|
||||
raise RuntimeError(f"error reading credentials file: {e}")
|
||||
|
||||
return username, password, encryption_key
|
||||
|
||||
def get_exhaust_temp():
|
||||
commands_to_try = [
|
||||
["sensor", "get", "Exhaust Temp"],
|
||||
["sdr", "type", "temperature"],
|
||||
["sensor", "list"],
|
||||
["sdr", "elist", "full"],
|
||||
]
|
||||
|
||||
debug_sections = []
|
||||
session_error_seen = False
|
||||
for args in commands_to_try:
|
||||
cmd, rc, out, err = run_ipmi_raw(args)
|
||||
if has_ipmi_session_error(err):
|
||||
session_error_seen = True
|
||||
cmd_text = " ".join(cmd)
|
||||
section = [
|
||||
f"Command: {cmd_text}",
|
||||
f"Return code: {rc}",
|
||||
"STDOUT:",
|
||||
out.strip() or "<empty>",
|
||||
"STDERR:",
|
||||
err.strip() or "<empty>",
|
||||
]
|
||||
debug_sections.append("\n".join(section))
|
||||
|
||||
# Parse explicit sensor-get output first.
|
||||
if args[:2] == ["sensor", "get"] and out:
|
||||
m = re.search(r"Sensor\s+Reading\s*:\s*(-?\d+(?:\.\d+)?)\b.*degrees\s*C", out, re.IGNORECASE)
|
||||
if m:
|
||||
return int(float(m.group(1)))
|
||||
|
||||
# Parse table outputs that have pipe-delimited sensor rows.
|
||||
for line in out.splitlines():
|
||||
parts = [p.strip() for p in line.split("|")]
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
|
||||
sensor_name = parts[0]
|
||||
normalized_name = " ".join(sensor_name.lower().split())
|
||||
if not (normalized_name == "exhaust temp" or normalized_name.startswith("exhaust temp ")):
|
||||
continue
|
||||
|
||||
for part in parts[1:]:
|
||||
m = re.search(r"(-?\d+(?:\.\d+)?)\s*degrees\s*C", part, re.IGNORECASE)
|
||||
if m:
|
||||
return int(float(m.group(1)))
|
||||
|
||||
if session_error_seen:
|
||||
raise RuntimeError(
|
||||
"Failed to establish an IPMI session. "
|
||||
"Check host/credentials, then try different options like "
|
||||
"--interface lan --cipher 3 or --interface lanplus --cipher 17.\n\n"
|
||||
+ "Debug output from attempted commands:\n\n"
|
||||
+ "\n\n---\n\n".join(debug_sections)
|
||||
)
|
||||
|
||||
raise RuntimeError(
|
||||
"Failed to read Exhaust Temp from ipmitool output.\n"
|
||||
+ "Debug output from attempted commands:\n\n"
|
||||
+ "\n\n---\n\n".join(debug_sections)
|
||||
)
|
||||
|
||||
def main():
|
||||
# parse CLI args (IPMI host can be overridden with -H/--host)
|
||||
parser = argparse.ArgumentParser(description="Set fan speed via IPMI")
|
||||
parser.add_argument("-H", "--host", default="127.0.0.1", help="IPMI host/IP (default: %(default)s)")
|
||||
parser.add_argument("-H", "--host", required=True, help="IPMI host/IP")
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--credentials",
|
||||
default="/etc/credentials",
|
||||
help="Path to credentials file (default: %(default)s)",
|
||||
)
|
||||
parser.add_argument("--interface", default="lanplus", choices=["lanplus", "lan"], help="IPMI interface (default: %(default)s)")
|
||||
parser.add_argument("--cipher", type=int, default=None, help="Optional IPMI cipher suite ID (e.g. 3 or 17)")
|
||||
args = parser.parse_args()
|
||||
|
||||
global IPMIHOST
|
||||
# set global IPMIHOST so run_ipmi() uses the provided host
|
||||
global IPMIHOST, IPMIINTERFACE, IPMICIPHER, IPMIUSER, IPMIPW, IPMIEK
|
||||
# set globals so run_ipmi() uses provided connection settings and credentials
|
||||
IPMIHOST = args.host
|
||||
IPMIINTERFACE = args.interface
|
||||
IPMICIPHER = args.cipher
|
||||
IPMIUSER, IPMIPW, IPMIEK = load_credentials(args.credentials)
|
||||
|
||||
ts_print(f"{IPMIHOST}: Fan speed check for host {IPMIHOST}")
|
||||
try:
|
||||
temp = get_ambient_temp()
|
||||
temp = get_exhaust_temp()
|
||||
ts_print(f"{IPMIHOST}: Exhaust temperature: {temp} C")
|
||||
except Exception as e:
|
||||
ts_print(f"{IPMIHOST}: Error reading temperature: {e}")
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/python3
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import sys
|
||||
import urllib3
|
||||
import redfish
|
||||
|
||||
# Suppress SSL warnings for self-signed iLO certificates
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
parser = argparse.ArgumentParser(description="Power off an HPE server via iLO Redfish")
|
||||
parser.add_argument("hostname", help="iLO hostname or IP address")
|
||||
parser.add_argument("-c", "--credentials", default="/etc/ilo_credentials",
|
||||
help="Path to credentials file (default: /etc/ilo_credentials)")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Read credentials from file (chmod 600 recommended: sudo chmod 600 /etc/ilo_credentials)
|
||||
# File format:
|
||||
# [ilo]
|
||||
# username = root
|
||||
# password = yourpassword
|
||||
cred_path = args.credentials
|
||||
if not os.path.exists(cred_path):
|
||||
print(f"Error: credentials file not found: {cred_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(cred_path)
|
||||
try:
|
||||
LOGIN_ACCOUNT = config.get("ilo", "username", fallback="root")
|
||||
LOGIN_PASSWORD = config.get("ilo", "password")
|
||||
except (configparser.NoSectionError, configparser.NoOptionError) as e:
|
||||
print(f"Error reading credentials file: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
BASE_URL = f"https://{args.hostname}"
|
||||
|
||||
REDFISHOBJ = redfish.RedfishClient(
|
||||
base_url=BASE_URL,
|
||||
username=LOGIN_ACCOUNT,
|
||||
password=LOGIN_PASSWORD,
|
||||
)
|
||||
REDFISHOBJ.login(auth="session")
|
||||
|
||||
# Discover the correct reset action URI from the system resource
|
||||
sys_response = REDFISHOBJ.get("/redfish/v1/Systems/1/")
|
||||
reset_uri = sys_response.dict["Actions"]["#ComputerSystem.Reset"]["target"]
|
||||
|
||||
body = {"ResetType": "PushPowerButton"} # iLO 4: PushPowerButton = graceful shutdown; use "ForceOff" for hard power cut
|
||||
response = REDFISHOBJ.post(reset_uri, body=body)
|
||||
|
||||
print(f"Status: {response.status}")
|
||||
if response.status >= 400:
|
||||
print(f"Error: {response.read}")
|
||||
|
||||
REDFISHOBJ.logout()
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
DEFAULT_EK = "0000000000000000000000000000000000000000"
|
||||
|
||||
|
||||
def load_credentials(path):
|
||||
if not os.path.exists(path):
|
||||
print(f"Error: credentials file not found: {path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(path)
|
||||
|
||||
try:
|
||||
username = config.get("credentials", "username", fallback="root")
|
||||
password = config.get("credentials", "password")
|
||||
encryption_key = config.get("credentials", "encryption_key", fallback=DEFAULT_EK)
|
||||
except (configparser.NoSectionError, configparser.NoOptionError) as e:
|
||||
print(f"Error reading credentials file: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
return username, password, encryption_key
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description="Send IPMI power off")
|
||||
p.add_argument("-H", "--host", required=True, help="IPMI host address")
|
||||
p.add_argument(
|
||||
"-c",
|
||||
"--credentials",
|
||||
default="credentials",
|
||||
help="Path to credentials file (default: credentials)",
|
||||
)
|
||||
args = p.parse_args()
|
||||
|
||||
ipmi_user, ipmi_pw, ipmi_ek = load_credentials(args.credentials)
|
||||
|
||||
cmd = [
|
||||
"ipmitool",
|
||||
"-I", "lanplus",
|
||||
"-H", args.host,
|
||||
"-U", ipmi_user,
|
||||
"-P", ipmi_pw,
|
||||
"-y", ipmi_ek,
|
||||
"power", "off",
|
||||
]
|
||||
|
||||
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if proc.returncode != 0:
|
||||
print("ipmitool failed:", proc.stderr.strip(), file=sys.stderr)
|
||||
sys.exit(proc.returncode)
|
||||
|
||||
print(proc.stdout.strip())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
def ts_print(msg):
|
||||
"""ts_print message prefixed with a timestamp (YYYY-MM-DD HH:MM:SS)."""
|
||||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
print(f"{now} {msg}")
|
||||
|
||||
DEFAULT_EK = "0000000000000000000000000000000000000000"
|
||||
|
||||
|
||||
def load_credentials(path):
|
||||
if not os.path.exists(path):
|
||||
print(f"Error: credentials file not found: {path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(path)
|
||||
|
||||
try:
|
||||
username = config.get("ilo", "username", fallback="root")
|
||||
password = config.get("ilo", "password")
|
||||
encryption_key = config.get("ilo", "encryption_key", fallback=DEFAULT_EK)
|
||||
except (configparser.NoSectionError, configparser.NoOptionError) as e:
|
||||
print(f"Error reading credentials file: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
return username, password, encryption_key
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description="Send IPMI power on")
|
||||
p.add_argument("-H", "--host", required=True, help="IPMI host address")
|
||||
p.add_argument(
|
||||
"-c",
|
||||
"--credentials",
|
||||
default="credentials",
|
||||
help="Path to credentials file (default: credentials)",
|
||||
)
|
||||
args = p.parse_args()
|
||||
|
||||
ipmi_user, ipmi_pw, ipmi_ek = load_credentials(args.credentials)
|
||||
|
||||
cmd = [
|
||||
"ipmitool",
|
||||
"-I", "lanplus",
|
||||
"-H", args.host,
|
||||
"-U", ipmi_user,
|
||||
"-P", ipmi_pw,
|
||||
"-y", ipmi_ek,
|
||||
"power", "on",
|
||||
]
|
||||
print(f"Sending power on to {args.host}")
|
||||
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if proc.returncode != 0:
|
||||
print("ipmitool failed:", proc.stderr.strip(), file=sys.stderr)
|
||||
sys.exit(proc.returncode)
|
||||
print(proc.stdout.strip())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to read and parse Powerball numbers from a CSV file.
|
||||
"""
|
||||
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import List, Dict
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def read_powerball_csv(filepath: str) -> List[Dict]:
|
||||
"""
|
||||
Read a CSV file containing Powerball numbers.
|
||||
|
||||
Expected CSV format:
|
||||
Draw Date,Winning Numbers,Multiplier
|
||||
09/26/2020,11 21 27 36 62 24,3
|
||||
|
||||
Args:
|
||||
filepath: Path to the CSV file
|
||||
|
||||
Returns:
|
||||
List of dictionaries containing parsed powerball data
|
||||
"""
|
||||
powerball_data = []
|
||||
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as csvfile:
|
||||
reader = csv.DictReader(csvfile)
|
||||
|
||||
for row_num, row in enumerate(reader, start=2): # start=2 because row 1 is header
|
||||
try:
|
||||
# Skip empty rows
|
||||
if not any(row.values()):
|
||||
continue
|
||||
|
||||
# Parse the row
|
||||
draw_date = datetime.strptime(row['Draw Date'].strip(), '%m/%d/%Y')
|
||||
|
||||
# Parse winning numbers - filter out empty strings
|
||||
numbers_str = row['Winning Numbers'].strip()
|
||||
winning_numbers = [int(n) for n in numbers_str.split() if n.strip()]
|
||||
|
||||
multiplier = int(row['Multiplier'].strip())
|
||||
|
||||
powerball_data.append({
|
||||
'draw_date': draw_date,
|
||||
'date_str': draw_date.strftime('%Y-%m-%d'),
|
||||
'winning_numbers': winning_numbers,
|
||||
'multiplier': multiplier
|
||||
})
|
||||
except ValueError as e:
|
||||
print(f"Warning: Skipping row {row_num} due to error: {e}")
|
||||
print(f" Row data: {row}")
|
||||
continue
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File '{filepath}' not found.")
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"Error: Failed to read CSV file - {e}")
|
||||
return []
|
||||
|
||||
return powerball_data
|
||||
|
||||
|
||||
def display_powerball_data(data: List[Dict]) -> None:
|
||||
"""
|
||||
Display powerball data in a formatted table.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
"""
|
||||
if not data:
|
||||
print("No data to display.")
|
||||
return
|
||||
|
||||
print(f"{'Draw Date':<12} {'Winning Numbers':<30} {'Multiplier':<10}")
|
||||
print("-" * 52)
|
||||
|
||||
for entry in data:
|
||||
numbers_str = ' '.join(map(str, entry['winning_numbers']))
|
||||
print(f"{entry['date_str']:<12} {numbers_str:<30} {entry['multiplier']:<10}")
|
||||
|
||||
|
||||
def analyze_most_frequent_numbers(data: List[Dict]) -> None:
|
||||
"""
|
||||
Analyze and display the most frequent number in each slot position.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
"""
|
||||
if not data:
|
||||
print("No data to analyze.")
|
||||
return
|
||||
|
||||
# Initialize lists to hold numbers for each position
|
||||
num_positions = len(data[0]['winning_numbers'])
|
||||
position_numbers = [[] for _ in range(num_positions)]
|
||||
|
||||
# Collect all numbers for each position
|
||||
for entry in data:
|
||||
for position, number in enumerate(entry['winning_numbers']):
|
||||
position_numbers[position].append(number)
|
||||
|
||||
# Find most common number in each position
|
||||
print("\n" + "=" * 60)
|
||||
print("Most Frequent Numbers by Slot Position")
|
||||
print("=" * 60)
|
||||
|
||||
most_frequent = []
|
||||
for position, numbers in enumerate(position_numbers, start=1):
|
||||
counter = Counter(numbers)
|
||||
most_common_num, frequency = counter.most_common(1)[0]
|
||||
most_frequent.append(most_common_num)
|
||||
percentage = (frequency / len(numbers)) * 100
|
||||
print(f"Position {position}: {most_common_num:<3} (appears {frequency} times, {percentage:.1f}%)")
|
||||
|
||||
print("-" * 60)
|
||||
print(f"Most frequent numbers combined: {' '.join(map(str, most_frequent))}")
|
||||
|
||||
# Analyze most frequent number across first 5 positions combined
|
||||
print("\n" + "=" * 60)
|
||||
print("Additional Analysis")
|
||||
print("=" * 60)
|
||||
|
||||
# Combine all numbers from positions 1-5
|
||||
first_five_combined = []
|
||||
for i in range(min(5, num_positions)):
|
||||
first_five_combined.extend(position_numbers[i])
|
||||
|
||||
if first_five_combined:
|
||||
counter_first_five = Counter(first_five_combined)
|
||||
top_five_numbers = counter_first_five.most_common(5)
|
||||
print("Top 5 most drawn numbers in first 5 positions combined:")
|
||||
for rank, (number, frequency) in enumerate(top_five_numbers, start=1):
|
||||
percentage = (frequency / len(first_five_combined)) * 100
|
||||
print(f" {rank}. {number:<3} (appears {frequency} times, {percentage:.1f}%)")
|
||||
|
||||
# Analyze the sixth position (Powerball)
|
||||
most_common_sixth = None
|
||||
if num_positions >= 6:
|
||||
sixth_position_numbers = position_numbers[5]
|
||||
counter_sixth = Counter(sixth_position_numbers)
|
||||
most_common_sixth, freq_sixth = counter_sixth.most_common(1)[0]
|
||||
percentage_sixth = (freq_sixth / len(sixth_position_numbers)) * 100
|
||||
print(f"\nMost drawn number in position 6 (Powerball): {most_common_sixth} (appears {freq_sixth} times, {percentage_sixth:.1f}%)")
|
||||
|
||||
# Return statistics for prediction
|
||||
return {
|
||||
'top_five_combined': [num for num, freq in top_five_numbers] if first_five_combined else [],
|
||||
'most_common_powerball': most_common_sixth
|
||||
}
|
||||
|
||||
|
||||
def generate_suggested_combination(stats: dict) -> None:
|
||||
"""
|
||||
Generate a suggested combination based on statistical analysis.
|
||||
|
||||
Args:
|
||||
stats: Dictionary containing statistical analysis results
|
||||
"""
|
||||
print("\n" + "=" * 60)
|
||||
print("Suggested Combination Based on Statistical Analysis")
|
||||
print("=" * 60)
|
||||
|
||||
print("\n⚠️ DISCLAIMER: This is purely statistical analysis.")
|
||||
print("Past results do NOT predict future outcomes.")
|
||||
print("Each draw is random and independent.\n")
|
||||
|
||||
top_five = stats['top_five_combined']
|
||||
powerball = stats['most_common_powerball']
|
||||
|
||||
if len(top_five) >= 5 and powerball:
|
||||
# Use the top 5 most frequent numbers from positions 1-5
|
||||
suggested_numbers = sorted(top_five[:5])
|
||||
|
||||
print(f"Suggested white ball numbers: {' '.join(map(str, suggested_numbers))}")
|
||||
print(f"Suggested Powerball number: {powerball}")
|
||||
print()
|
||||
print(f"Complete combination: {' '.join(map(str, suggested_numbers))} + {powerball}")
|
||||
print()
|
||||
print("This combination is based on:")
|
||||
print(" • The 5 most frequently drawn numbers across all white ball positions")
|
||||
print(f" • The most frequently drawn Powerball number ({powerball})")
|
||||
else:
|
||||
print("Insufficient data to generate a suggestion.")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function."""
|
||||
# Default to 'powerball_numbers.csv' in the same directory as the script
|
||||
script_dir = Path(__file__).parent
|
||||
csv_file = script_dir / 'powerball_numbers.csv'
|
||||
|
||||
# You can also specify a different file path here
|
||||
# csv_file = Path('path/to/your/file.csv')
|
||||
|
||||
print(f"Reading Powerball numbers from: {csv_file}\n")
|
||||
|
||||
powerball_data = read_powerball_csv(str(csv_file))
|
||||
|
||||
if powerball_data:
|
||||
print(f"Successfully loaded {len(powerball_data)} records.\n")
|
||||
display_powerball_data(powerball_data)
|
||||
stats = analyze_most_frequent_numbers(powerball_data)
|
||||
generate_suggested_combination(stats)
|
||||
else:
|
||||
print("Failed to load powerball data.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user